home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 October: Technology Seed / ADC Seed CD - October 1999.toast / FireWire / FireWire_2.0_SDK / Source / AVTransport / FWAVCDriver / FWAVCDriver.c next >
Encoding:
C/C++ Source or Header  |  1999-04-12  |  97.3 KB  |  3,317 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        FWAVCDriver.c
  3.  
  4.     Contains:    Driver software for AVC transport control.
  5.  
  6.     Written by:    Erik Staats
  7.  
  8.     Copyright:    © 1996-1997 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.       <FW32>     3/18/97    ES        Changed driver description version to final.
  13.       <FW31>     3/10/97    ES        Fixed problem with inserting the correct number of empty packets
  14.                                     in a buffer group.
  15.       <FW30>     3/10/97    ES        Removed use of kDVFrameRateNumerator/Denominator and used
  16.                                     kPlayFrameRateNumerator/Denominator.
  17.       <FW29>     3/10/97    ES        Changed to remove empty packets to resynchronize after lost
  18.                                     cycles. Changed to loop over one frame on playback instead of
  19.                                     three. Changed to play at a settable frame rate (29.97 Hz in
  20.                                     header) with settable buffer group sizes. Improved memory
  21.                                     allocation for playback.
  22.       <FW28>      3/3/97    ES        Changed to use DCLTimeStamp to resynchronize SYT field when we
  23.                                     miss cycles.
  24.       <FW27>     2/14/97    ES        Added kFWDCLOpDynamicFlag to jump ops we intend to modify.
  25.       <FW26>     1/16/97    ES        Added use of DCLUpdateList commands.
  26.       <FW25>      1/1/97    ES        Added UpdateDCLList command to record DCL program.
  27.       <FW24>    12/27/96    ES        Changed FWAVCTerminate to check if gpFWAVCDriverData is nil.
  28.       <FW23>    12/27/96    ES        Changed a bunch of "FWDriver"s to "FWClient"s.
  29.       <FW22>    12/22/96    ES        Changed IsochPortAction to IsochPortControl.
  30.       <FW21>     12/5/96    ES        Added an ifdef to conditionaly compile a driver with the correct
  31.                                     driver name or a driver with an alternate driver name.
  32.       <FW20>    10/22/96    ES        Changed to generic driver model.
  33.       <FW19>     10/4/96    ES        Replaced DCLSetPacketAttributes with DCLSetTagSyncBits.
  34.       <FW18>     9/27/96    ES        Changed to use set driver interface calls rather than driver
  35.                                     interface table.
  36.       <FW17>     9/24/96    GG        Added rewind, review, whatchadoing, fastforward, fastplay, slow,
  37.                                     nextframe, and previousframe, and pause.
  38.       <FW16>     9/16/96    ES        Changed FireWire driver interface procs to return command
  39.                                     acceptance.
  40.       <FW15>      9/4/96    ES        Added more deallocation.
  41.       <FW14>      9/3/96    ES        Added line to nil out reset notification proc in driver
  42.                                     interface table.
  43.       <FW13>     8/29/96    ES        Changed FWRegisterDriver to take driver interface proc table.
  44.       <FW12>     8/28/96    ES        Changed the way trial works in InitIsochPort.
  45.       <FW11>     8/26/96    ES        Changed to use new command object interface.
  46.       <FW10>     8/26/96    ES        Changed to accurately set SID field in the CIP header. Also,
  47.                                     changed some constant names.
  48.        <FW9>     8/19/96    ES        Changed to use separate stop and start isochronous param blocks
  49.                                     for handling DV send overruns.
  50.        <FW8>     8/16/96    ES        Changed FWAllocateLocalIsochronousPort to take param block. Made
  51.                                     some other minor modifications.
  52.        <FW7>     8/15/96    ES        Made isoch channel and port stuff asynchronous. Added overrun
  53.                                     handling to DV output.
  54.        <FW6>      8/2/96    ES        Updated for more isochronous changes.
  55.        <FW5>      8/1/96    ES        Took out unused local variables.
  56.        <FW4>     7/31/96    ES        Changed to use new isochronous buffer architecture.
  57.        <FW3>      7/8/96    ES        Added dump and 3 frame snap shot loop playing capabilities.
  58.        <FW2>     6/20/96    ES        Filled in contains and written by fields.
  59.        <FW1>     6/20/96    ES        first checked in
  60.  
  61. */
  62.  
  63. #include <Types.h>
  64. #include <Errors.h>
  65. #include <Devices.h>
  66. #include <DriverServices.h>
  67. #include <FireWire.h>
  68. #include <AVTransport.h>
  69. #include <FWAVCDriver.h>
  70. /*zzz*/
  71. #include <TextUtils.h>
  72. #include <stdio.h>
  73. char    debugStr[256];
  74. /*zzz*/
  75. #define        PLAY            0x0000c375
  76. #define        SLOW            0x0000c335
  77. #define        PLAYBACK        0x0000c348
  78. #define        FASTPLAY        0x0000c33e
  79. #define        PAUSE            0x0000c37d
  80. #define        REVIEW            0x0000c34e
  81. #define        NEXTFRAME        0x0000c330
  82. #define        PREVIOUSFRAME    0x0000c340
  83.  
  84.  
  85. ////////////////////////////////////////////////////////////////////////////////
  86. //
  87. // Internal procedure prototypes.
  88. //
  89.  
  90. static OSStatus    FWAVCInitIsochPort (
  91.     FWClientInitIsochPortParamsPtr
  92.                                 pInitIsochPortParams,
  93.     UInt32                        *pCommandAcceptance);
  94.  
  95. static OSStatus    FWAVCReleaseIsochPort (
  96.     FWClientReleaseIsochPortParamsPtr
  97.                                 pReleaseIsochPortParams,
  98.     UInt32                        *pCommandAcceptance);
  99.  
  100. static OSStatus    FWAVCStartIsochPort (
  101.     FWClientIsochPortControlParamsPtr
  102.                                 pIsochPortControlParams,
  103.     UInt32                        *pCommandAcceptance);
  104.  
  105. static OSStatus    FWAVCStopIsochPort (
  106.     FWClientIsochPortControlParamsPtr
  107.                                 pIsochPortControlParams,
  108.     UInt32                        *pCommandAcceptance);
  109.  
  110. static OSStatus    FWAVCInitialize (
  111.     RegEntryIDPtr                pRegEntryID);
  112.  
  113. static OSStatus    FWAVCTerminate (void);
  114.  
  115. static OSStatus    AVTDriverInterface (
  116.     AVTInterfaceParamsPtr        pAVTInterfaceParams);
  117.  
  118. static OSStatus    FWAVCPlay (
  119.     AVTPlayParamsPtr            pAVTPlayParams);
  120.  
  121. static OSStatus    FWAVCStop (
  122.     AVTStopParamsPtr            pAVTStopParams);
  123.  
  124. static OSStatus FWAVCRewind (
  125.     AVTRewindParamsPtr            pAVTRewindParams);
  126.  
  127. static OSStatus FWAVCReview (
  128.     AVTReviewParamsPtr            pAVTReviewParams);
  129.  
  130. static OSStatus FWAVCFastForward (
  131.     AVTFastForwardParamsPtr        pAVTFastForwardParams);
  132.  
  133. static OSStatus FWAVCFastPlay (
  134.     AVTFastPlayParamsPtr        pAVTFastPlayParams);
  135.  
  136. static OSStatus FWAVCPause (
  137.     AVTPauseParamsPtr            pAVTPauseParams);
  138.  
  139. static OSStatus FWAVCWhatchaDoing (
  140.     AVTWhatchaDoingParamsPtr    pAVTWhatchaDoingParams);
  141.  
  142. static OSStatus FWAVCSlow (
  143.     AVTSlowParamsPtr            pAVTSlowParams);
  144.  
  145. static OSStatus FWAVCNextFrame (
  146.     AVTNextFrameParamsPtr        pAVTNextFrameParams);
  147.  
  148. static OSStatus FWAVCPreviousFrame (
  149.     AVTPreviousFrameParamsPtr    pAVTPreviousFrameParams);
  150.  
  151. static OSStatus    FWAVCDump (
  152.     AVTDumpParamsPtr            pAVTDumpParams);
  153.  
  154. static OSStatus    FWAVCPlaySnapShot (
  155.     AVTPlaySnapShotParamsPtr    pAVTPlaySnapShotParams);
  156.  
  157. static OSStatus    FWAVCStopSnapShot (
  158.     AVTInterfaceParamsPtr        pAVTInterfaceParams);
  159.  
  160. static void    FWAVCDVPingPong (
  161.     DCLCommandPtr                pDCLCommandPtr);
  162.  
  163. static void    FWAVCHandleDVSend (
  164.     DCLCommandPtr                pDCLCommand);
  165.  
  166. static void    FWAVCUpdateDVSendBuffers (
  167.     DCLCommandPtr                pDCLCommandPtr);
  168.  
  169. static void    FWAVCHandleDVSendUnderrun (
  170.     DCLCommandPtr                pDCLCommandPtr);
  171.  
  172. static void    FWAVCHandleDVSendUnderrunStopIsochronousChannelCompletionProc (
  173.     FWCommandObjectID            fwCommandObjectID,
  174.     OSStatus                    commandStatus,
  175.     UInt32                        completionProcData);
  176.  
  177. static void    FWAVCClientCommandCompletionProc (
  178.     FWCommandObjectID            fwCommandObjectID,
  179.     OSStatus                    commandStatus,
  180.     UInt32                        completionProcData);
  181.  
  182. static FWAVCPlayBufferGroupDataPtr    FWAVCAllocatePlayBufferGroup (
  183.     FWAVCDriverDataPtr            pFWAVCDriverData);
  184.  
  185. static void    FWAVCDeallocatePlayBufferGroup (
  186.     FWAVCPlayBufferGroupDataPtr    pFWAVCPlayBufferGroupData);
  187.  
  188. static OSStatus    FWAVCCreatePlayBufferGroupUpdateList (
  189.     FWAVCPlayBufferGroupDataPtr    pFWAVCPlayBufferGroupData);
  190.  
  191. static DCLCommandPtr    FWAVCAllocateDCLCommand (
  192.     DCLCommandPoolPtr            pDCLCommandPool,
  193.     UInt32                        dclSize);
  194.  
  195. static DCLCommandBlockPtr    FWAVCAllocateDCLCommandBlock (
  196.     DCLCommandPoolPtr            pDCLCommandPool);
  197.  
  198. static void    FWAVCDeallocateDCLCommandBlock (
  199.     DCLCommandBlockPtr            pDCLCommandBlock);
  200.  
  201. static DCLCommandPoolPtr    FWAVCAllocateDCLCommandPool (void);
  202.  
  203. static void    FWAVCDeallocateDCLCommandPool (
  204.     DCLCommandPoolPtr            pDCLCommandPool);
  205.  
  206. static UInt32    FWAVCAddCycleTimeToCycleTime (
  207.     UInt32                        cycleTime1,
  208.     UInt32                        cycleTime2);
  209.  
  210. static UInt32    FWAVCSubtractCycleTimeFromCycleTime (
  211.     UInt32                        cycleTime1,
  212.     UInt32                        cycleTime2);
  213.  
  214. static UInt32    FWAVCConvertFractionalSecondsToCycleTime (
  215.     UInt32                        secondsNumerator,
  216.     UInt32                        secondsDenominator);
  217.  
  218.  
  219. ////////////////////////////////////////////////////////////////////////////////
  220. //
  221. // The driver descriptor.
  222. //
  223.  
  224. DriverDescription                 TheDriverDescription =
  225. {
  226.     kTheDescriptionSignature,
  227.     kInitialDriverDescriptor,
  228.     {
  229. #ifdef FWAVCAlternateDriver
  230.         "\pfwa02d,10000",
  231. #else
  232.         "\pfwa02d,10001",
  233. #endif
  234.         1, 0, finalStage, 1,
  235.     },
  236.     {
  237.         kDriverIsUnderExpertControl,
  238.         "\pFWAVCDriver",
  239.     },
  240.  
  241.     1,
  242.     kServiceCategoryNdrvDriver,
  243.     kNdrvTypeIsAVTransport,
  244.     1,0,0,0
  245. };
  246.  
  247.  
  248. ////////////////////////////////////////////////////////////////////////////////
  249. //
  250. // Global driver data.
  251. //
  252.  
  253. FWAVCDriverDataPtr                gpFWAVCDriverData = nil;
  254.  
  255.  
  256. ////////////////////////////////////////////////////////////////////////////////
  257. //
  258. // DoDriverIO
  259. //
  260. //   Main entry point.
  261. //
  262.  
  263. OSErr    DoDriverIO(
  264.     AddressSpaceID                addressSpaceID,
  265.     IOCommandID                    ioCommandID,
  266.     IOCommandContents            ioCommandContents,
  267.     IOCommandCode                ioCommandCode,
  268.     IOCommandKind                ioCommandKind)
  269. {
  270.     CntrlParamPtr                pCntrlParam;
  271.     OSErr                        err = noErr;
  272.  
  273.     switch (ioCommandCode)
  274.     {
  275.         case kInitializeCommand :
  276.             err = FWAVCInitialize (&ioCommandContents.initialInfo->deviceEntry);
  277.             break;
  278.  
  279.         case kFinalizeCommand :
  280.             err = FWAVCTerminate ();
  281.  
  282.         case kOpenCommand :
  283.             break;
  284.  
  285.         case kCloseCommand :
  286.             break;
  287.  
  288.         case kControlCommand :
  289.             pCntrlParam = (CntrlParamPtr) ioCommandContents.pb;
  290.             if (pCntrlParam->csCode == cscAVTCommand)
  291.             {
  292.                 err = AVTDriverInterface
  293.                         (*((AVTInterfaceParamsPtr *) &(pCntrlParam->csParam[0])));
  294.             }
  295.             else
  296.             {
  297.                 err = controlErr;
  298.             }
  299.             break;
  300.  
  301.         case kStatusCommand :
  302.             err = statusErr;
  303.             break;
  304.  
  305.         default :
  306.             err = paramErr;
  307.     }
  308.  
  309.     // We're complete.
  310.     if (ioCommandKind == kImmediateIOCommandKind)
  311.         return (err);
  312.     else
  313.         return (IOCommandIsComplete (ioCommandID, err));
  314.  
  315.     return (err);
  316. }
  317.  
  318.  
  319. ////////////////////////////////////////////////////////////////////////////////
  320. //
  321. // FWAVCInitIsochPort
  322. //
  323. //   This routine initializes an isochronous port for the AVC camera.  If
  324. // the request is for the talking port, this routine sets up the camera's
  325. // isochronous port.  If the request is for the listening port, this routine
  326. // sets up the local node's isochronous port.
  327. //
  328.  
  329. static OSStatus    FWAVCInitIsochPort(
  330.     FWClientInitIsochPortParamsPtr
  331.                                 pInitIsochPortParams,
  332.     UInt32                        *pCommandAcceptance)
  333. {
  334.     FWAVCDriverDataPtr            pFWAVCDriverData;
  335.     FWCommandObjectID            isochPortCommandObjectID;
  336.     IsochChannelID                isochChannelID;
  337.     UInt32                        channelNum;
  338.     UInt32                        speed;
  339.     Boolean                        portIsTalker;
  340.     Boolean                        trial;
  341.     OSStatus                    status = noErr;
  342.  
  343.     // Get our driver data.
  344.     pFWAVCDriverData = (FWAVCDriverDataPtr)
  345.         pInitIsochPortParams->fwClientInterfaceParams.fwClientSpecificData;
  346.  
  347.     // Get ID for this channel.
  348.     isochChannelID = pInitIsochPortParams->fwClientIsochPortParams.isochChannelID;
  349.  
  350.     // Get speed and channel number.
  351.     speed = pInitIsochPortParams->speed;
  352.     channelNum = pInitIsochPortParams->channelNum;
  353.  
  354.     // Is this request for the talking port?
  355.     portIsTalker = pInitIsochPortParams->fwClientIsochPortParams.portIsTalker;
  356.  
  357.     // Is this a trial?
  358.     trial = pInitIsochPortParams->trial;
  359.  
  360.     // Initialize.
  361.     if (isochChannelID == pFWAVCDriverData->recordIsochChannelID)
  362.     {
  363.         if (portIsTalker)
  364.         {
  365.             // Port is for camera.
  366.             if (!trial)
  367.             {
  368.                 // Check params.
  369.                 //zzz We only do channel 63.
  370.                 if ((speed > kFWSpeed100MBit) || (channelNum != 63))
  371.                     status = paramErr;
  372.             }
  373.             else
  374.             {
  375.                 // Return supported channel numbers.
  376.                 pInitIsochPortParams->supportedChannelNumHi = 0x00000000;
  377.                 pInitIsochPortParams->supportedChannelNumLo = 0x00000001;
  378.  
  379.                 // Return supported speed.
  380.                 if (speed > kFWSpeed100MBit)
  381.                     pInitIsochPortParams->speed = kFWSpeed100MBit;
  382.             }
  383.         }
  384.         else
  385.         {
  386.             // Port is for local node.
  387.             if (!trial)
  388.             {
  389.                 // Allocate an isoch port ID.
  390.                 status = FWAllocateIsochPortID (&(pFWAVCDriverData->isochPortID),
  391.                                                 pFWAVCDriverData->recordDCLProgramID,
  392.                                                 channelNum,
  393.                                                 speed,
  394.                                                 portIsTalker);
  395.  
  396.                 // Send an allocate isoch port command to allocate port for listening.
  397.                 if (status == noErr)
  398.                 {
  399.                     // Set up command object.
  400.                     isochPortCommandObjectID = pFWAVCDriverData->isochPortCommandObjectID;
  401.                     FWSetFWCommandParams (isochPortCommandObjectID,
  402.                                           (FWReferenceID) pFWAVCDriverData->fwDriverID,
  403.                                           kFWCommandSyncFlag,
  404.                                           nil,
  405.                                           0);
  406.                     FWSetIsochPortCommandIsochPortID (isochPortCommandObjectID,
  407.                                                       pFWAVCDriverData->isochPortID);
  408.  
  409.                     // Send command.
  410.                     status = FWAllocateLocalIsochronousPort (isochPortCommandObjectID);
  411.                 }
  412.             }
  413.             else
  414.             {
  415.                 // Return supported channel numbers.
  416.                 pInitIsochPortParams->supportedChannelNumHi = 0x00000000;
  417.                 pInitIsochPortParams->supportedChannelNumLo = 0x00000001;
  418.  
  419.                 // Return supported speed.
  420.                 if (speed > kFWSpeed100MBit)
  421.                     pInitIsochPortParams->speed = kFWSpeed100MBit;
  422.             }
  423.         }
  424.     }
  425.     else
  426.     {
  427.         if (portIsTalker)
  428.         {
  429.             // Port is for local node.
  430.             if (!trial)
  431.             {
  432.                 // Allocate an isoch port ID.
  433.                 status = FWAllocateIsochPortID (&(pFWAVCDriverData->isochPortID),
  434.                                                 pFWAVCDriverData->playDCLProgramID,
  435.                                                 channelNum,
  436.                                                 speed,
  437.                                                 portIsTalker);
  438.  
  439.                 // Send an allocate isoch port command to allocate port for talking.
  440.                 if (status == noErr)
  441.                 {
  442.                     // Set up command object.
  443.                     isochPortCommandObjectID = pFWAVCDriverData->isochPortCommandObjectID;
  444.                     FWSetFWCommandParams (isochPortCommandObjectID,
  445.                                           (FWReferenceID) pFWAVCDriverData->fwDriverID,
  446.                                           kFWCommandSyncFlag,
  447.                                           nil,
  448.                                           0);
  449.                     FWSetIsochPortCommandIsochPortID (isochPortCommandObjectID,
  450.                                                       pFWAVCDriverData->isochPortID);
  451.  
  452.                     // Send command.
  453.                     status = FWAllocateLocalIsochronousPort (isochPortCommandObjectID);
  454.                 }
  455.             }
  456.             else
  457.             {
  458.                 // Return supported channel numbers.
  459.                 pInitIsochPortParams->supportedChannelNumHi = 0x00000000;
  460.                 pInitIsochPortParams->supportedChannelNumLo = 0x00000001;
  461.  
  462.                 // Return supported speed.
  463.                 if (speed > kFWSpeed100MBit)
  464.                     pInitIsochPortParams->speed = kFWSpeed100MBit;
  465.             }
  466.         }
  467.         else
  468.         {
  469.             // Port is for camera.
  470.             if (!trial)
  471.             {
  472.                 // Check params.
  473.                 //zzz We only do channel 63.
  474.                 if ((speed > kFWSpeed100MBit) || (channelNum != 63))
  475.                     status = paramErr;
  476.             }
  477.             else
  478.             {
  479.                 // Return supported channel numbers.
  480.                 pInitIsochPortParams->supportedChannelNumHi = 0x00000000;
  481.                 pInitIsochPortParams->supportedChannelNumLo = 0x00000001;
  482.  
  483.                 // Return supported speed.
  484.                 if (speed > kFWSpeed100MBit)
  485.                     pInitIsochPortParams->speed = kFWSpeed100MBit;
  486.             }
  487.         }
  488.     }
  489.  
  490.     // Complete FireWire client command.
  491.     FWClientCommandIsComplete
  492.         (pInitIsochPortParams->fwClientInterfaceParams.fwClientCommandID, status);
  493.  
  494.     // Return command acceptance.
  495.     //zzz is this the right way?  If we've completed the command, we can accept more.
  496.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  497.  
  498.     return (status);
  499. }
  500.  
  501.  
  502. ////////////////////////////////////////////////////////////////////////////////
  503. //
  504. // FWAVCReleaseIsochPort
  505. //
  506. //   This procedure releases resources allocated for the isochronous channel.
  507. // If the channel is a listener, this routine will release the local
  508. // isochronous port.
  509. //
  510.  
  511. static OSStatus    FWAVCReleaseIsochPort(
  512.     FWClientReleaseIsochPortParamsPtr
  513.                                 pReleaseIsochPortParams,
  514.     UInt32                        *pCommandAcceptance)
  515. {
  516.     FWAVCDriverDataPtr            pFWAVCDriverData;
  517.     FWCommandObjectID            isochPortCommandObjectID;
  518.     IsochChannelID                isochChannelID;
  519.     Boolean                        portIsTalker;
  520.     OSStatus                    status = noErr;
  521.  
  522.     // Get our driver data.
  523.     pFWAVCDriverData = (FWAVCDriverDataPtr)
  524.         pReleaseIsochPortParams->fwClientInterfaceParams.fwClientSpecificData;
  525.  
  526.     // Get ID for this channel.
  527.     isochChannelID = pReleaseIsochPortParams->fwClientIsochPortParams.isochChannelID;
  528.  
  529.     // Is this request for the talking port?
  530.     portIsTalker = pReleaseIsochPortParams->fwClientIsochPortParams.portIsTalker;
  531.  
  532.     if (isochChannelID == pFWAVCDriverData->recordIsochChannelID)
  533.     {
  534.         if (!portIsTalker)
  535.         {
  536.             // Set up command object to release port.
  537.             isochPortCommandObjectID = pFWAVCDriverData->isochPortCommandObjectID;
  538.             FWSetFWCommandParams (isochPortCommandObjectID,
  539.                                   (FWReferenceID) pFWAVCDriverData->fwDriverID,
  540.                                   kFWCommandSyncFlag,
  541.                                   nil,
  542.                                   0);
  543.             FWSetIsochPortCommandIsochPortID (isochPortCommandObjectID,
  544.                                               pFWAVCDriverData->isochPortID);
  545.  
  546.             // Send command.
  547.             FWReleaseLocalIsochronousPort (isochPortCommandObjectID);
  548.  
  549.             // Deallocate isoch port ID.
  550.             FWDeallocateIsochPortID (pFWAVCDriverData->isochPortID);
  551.         }
  552.     }
  553.     else
  554.     {
  555.         if (portIsTalker)
  556.         {
  557.             // Set up command object to release port.
  558.             isochPortCommandObjectID = pFWAVCDriverData->isochPortCommandObjectID;
  559.             FWSetFWCommandParams (isochPortCommandObjectID,
  560.                                   (FWReferenceID) pFWAVCDriverData->fwDriverID,
  561.                                   kFWCommandSyncFlag,
  562.                                   nil,
  563.                                   0);
  564.             FWSetIsochPortCommandIsochPortID (isochPortCommandObjectID,
  565.                                               pFWAVCDriverData->isochPortID);
  566.  
  567.             // Send command.
  568.             FWReleaseLocalIsochronousPort (isochPortCommandObjectID);
  569.  
  570.             // Deallocate isoch port ID.
  571.             FWDeallocateIsochPortID (pFWAVCDriverData->isochPortID);
  572.         }
  573.     }
  574.  
  575.     // Complete FireWire client command.
  576.     FWClientCommandIsComplete
  577.         (pReleaseIsochPortParams->fwClientInterfaceParams.fwClientCommandID, status);
  578.  
  579.     // Return command acceptance.
  580.     //zzz is this the right way?  If we've completed the command, we can accept more.
  581.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  582.  
  583.     return (status);
  584. }
  585.  
  586.  
  587. ////////////////////////////////////////////////////////////////////////////////
  588. //
  589. // FWAVCStartIsochPort
  590. //
  591. //   This procedure starts the isochronous channel.  If the channel is a
  592. // talker, this procedure will program the camera to start sending isochronous
  593. // data.  If the channel is a listener, this procedure will start the local
  594. // isochronous port.
  595. //
  596.  
  597. static OSStatus    FWAVCStartIsochPort(
  598.     FWClientIsochPortControlParamsPtr
  599.                                 pIsochPortControlParams,
  600.     UInt32                        *pCommandAcceptance)
  601. {
  602.     FWClientCommandID            fwClientCommandID;
  603.     FWAVCDriverDataPtr            pFWAVCDriverData;
  604.     FWCommandObjectID            isochPortCommandObjectID;
  605.     FWCommandObjectID            fcpCommandObjectID;
  606.     UInt32                        *pFCPPlayFrame;
  607.     IsochChannelID                isochChannelID;
  608.     Boolean                        portIsTalker;
  609.     Boolean                        completionIsPending = false;
  610.     OSStatus                    status = noErr;
  611.  
  612.     // Get our driver data.
  613.     pFWAVCDriverData = (FWAVCDriverDataPtr)
  614.         pIsochPortControlParams->fwClientInterfaceParams.fwClientSpecificData;
  615.  
  616.     // Get ID for this channel.
  617.     isochChannelID = pIsochPortControlParams->fwClientIsochPortParams.isochChannelID;
  618.  
  619.     // Is this request for the talking port?
  620.     portIsTalker = pIsochPortControlParams->fwClientIsochPortParams.portIsTalker;
  621.  
  622.     if (isochChannelID == pFWAVCDriverData->recordIsochChannelID)
  623.     {
  624.         if (portIsTalker)
  625.         {
  626.             // Set up FCP command to tell camera to start the transport.
  627.             fcpCommandObjectID = pFWAVCDriverData->asyncFCPCommandObjectID;
  628.             pFCPPlayFrame = pFWAVCDriverData->fcpCommandFrame;
  629.             pFCPPlayFrame[0] = 0x0020C375;
  630.  
  631.             fwClientCommandID =
  632.                 pIsochPortControlParams->fwClientInterfaceParams.fwClientCommandID;
  633.             FWSetFWCommandParams (fcpCommandObjectID,
  634.                                   (FWReferenceID) pFWAVCDriverData->fwDriverID,
  635.                                   0,
  636.                                   FWAVCClientCommandCompletionProc,
  637.                                   (UInt32) fwClientCommandID);
  638.  
  639.             FWSetFCPCommandParams (fcpCommandObjectID,
  640.                                    (Ptr) pFCPPlayFrame,
  641.                                    4,
  642.                                    (Ptr) pFCPPlayFrame,
  643.                                    40,
  644.                                    100 * durationMillisecond,
  645.                                    8,
  646.                                    0,
  647.                                    nil);
  648.  
  649.             // Send the FCP command.
  650.             status = FWSendFCPCommand (fcpCommandObjectID);
  651.             completionIsPending = true; //zzz what if above call returns an error?
  652.         }
  653.         else
  654.         {
  655.             // Set up command object to start port.
  656.             isochPortCommandObjectID = pFWAVCDriverData->startIsochPortCommandObjectID;
  657.             fwClientCommandID =
  658.                 pIsochPortControlParams->fwClientInterfaceParams.fwClientCommandID;
  659.             FWSetFWCommandParams (isochPortCommandObjectID,
  660.                                   (FWReferenceID) pFWAVCDriverData->fwDriverID,
  661.                                   0,
  662.                                   FWAVCClientCommandCompletionProc,
  663.                                   (UInt32) fwClientCommandID);
  664.             FWSetIsochPortCommandIsochPortID (isochPortCommandObjectID,
  665.                                               pFWAVCDriverData->isochPortID);
  666.  
  667.             // Send command to start port.
  668.             status = FWStartLocalIsochronousPort (isochPortCommandObjectID);
  669.             completionIsPending = true; //zzz what if above call returns an error?
  670.         }
  671.     }
  672.     else
  673.     {
  674.         if (portIsTalker)
  675.         {
  676.             // Set up command object to start port.
  677.             isochPortCommandObjectID = pFWAVCDriverData->startIsochPortCommandObjectID;
  678.             fwClientCommandID =
  679.                 pIsochPortControlParams->fwClientInterfaceParams.fwClientCommandID;
  680.             FWSetFWCommandParams (isochPortCommandObjectID,
  681.                                   (FWReferenceID) pFWAVCDriverData->fwDriverID,
  682.                                   0,
  683.                                   FWAVCClientCommandCompletionProc,
  684.                                   (UInt32) fwClientCommandID);
  685.             FWSetIsochPortCommandIsochPortID (isochPortCommandObjectID,
  686.                                               pFWAVCDriverData->isochPortID);
  687.  
  688.             // Send command to start port.
  689.             status = FWStartLocalIsochronousPort (isochPortCommandObjectID);
  690.             completionIsPending = true; //zzz what if above call returns an error?
  691.         }
  692.         else
  693.         {
  694.             //zzz don't do anything with camera yet.
  695.         }
  696.     }
  697.  
  698.     // Complete command if completion is not pending.
  699.     if (!completionIsPending)
  700.     {
  701.         status = FWClientCommandIsComplete
  702.                     (pIsochPortControlParams->fwClientInterfaceParams.fwClientCommandID,
  703.                      status);
  704.     }
  705.  
  706.     // Return command acceptance.
  707.     //zzz is this the right way?  If we've completed the command, we can accept more.
  708.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  709.  
  710.     return (status);
  711. }
  712.  
  713.  
  714. ////////////////////////////////////////////////////////////////////////////////
  715. //
  716. // FWAVCStopIsochPort
  717. //
  718. //   This procedure stop the isochronous channel.  If the channel is a
  719. // talker, this procedure will program the camera to stop sending isochronous
  720. // data.  If the channel is a listener, this procedure will stop the local
  721. // isochronous port.
  722. //
  723.  
  724. static OSStatus    FWAVCStopIsochPort(
  725.     FWClientIsochPortControlParamsPtr
  726.                                 pIsochPortControlParams,
  727.     UInt32                        *pCommandAcceptance)
  728. {
  729.     FWClientCommandID            fwClientCommandID;
  730.     FWAVCDriverDataPtr            pFWAVCDriverData;
  731.     FWCommandObjectID            isochPortCommandObjectID;
  732.     FWCommandObjectID            fcpCommandObjectID;
  733.     UInt32                        *pFCPStopFrame;
  734.     IsochChannelID                isochChannelID;
  735.     Boolean                        portIsTalker;
  736.     Boolean                        completionIsPending = false;
  737.     OSStatus                    status = noErr;
  738.  
  739.     // Get our driver data.
  740.     pFWAVCDriverData = (FWAVCDriverDataPtr)
  741.         pIsochPortControlParams->fwClientInterfaceParams.fwClientSpecificData;
  742.  
  743.     // Get ID for this channel.
  744.     isochChannelID = pIsochPortControlParams->fwClientIsochPortParams.isochChannelID;
  745.  
  746.     // Is this request for the talking port?
  747.     portIsTalker = pIsochPortControlParams->fwClientIsochPortParams.portIsTalker;
  748.  
  749.     if (isochChannelID == pFWAVCDriverData->recordIsochChannelID)
  750.     {
  751.         if (portIsTalker)
  752.         {
  753.             // Set up FCP command to tell camera to stop the transport.
  754.             fcpCommandObjectID = pFWAVCDriverData->asyncFCPCommandObjectID;
  755.             pFCPStopFrame = pFWAVCDriverData->fcpCommandFrame;
  756.             pFCPStopFrame[0] = 0x0020C460;
  757.  
  758.             fwClientCommandID =
  759.                 pIsochPortControlParams->fwClientInterfaceParams.fwClientCommandID;
  760.             FWSetFWCommandParams (fcpCommandObjectID,
  761.                                   (FWReferenceID) pFWAVCDriverData->fwDriverID,
  762.                                   0,
  763.                                   FWAVCClientCommandCompletionProc,
  764.                                   (UInt32) fwClientCommandID);
  765.  
  766.             FWSetFCPCommandParams (fcpCommandObjectID,
  767.                                    (Ptr) pFCPStopFrame,
  768.                                    4,
  769.                                    (Ptr) pFCPStopFrame,
  770.                                    40,
  771.                                    100 * durationMillisecond,
  772.                                    8,
  773.                                    0,
  774.                                    nil);
  775.  
  776.             // Send the FCP command.
  777.             status = FWSendFCPCommand (fcpCommandObjectID);
  778.             completionIsPending = true; //zzz what if above call returns an error?
  779.         }
  780.         else
  781.         {
  782.             // Set up command object to stop port.
  783.             isochPortCommandObjectID = pFWAVCDriverData->stopIsochPortCommandObjectID;
  784.             fwClientCommandID =
  785.                 pIsochPortControlParams->fwClientInterfaceParams.fwClientCommandID;
  786.             FWSetFWCommandParams (isochPortCommandObjectID,
  787.                                   (FWReferenceID) pFWAVCDriverData->fwDriverID,
  788.                                   0,
  789.                                   FWAVCClientCommandCompletionProc,
  790.                                   (UInt32) fwClientCommandID);
  791.             FWSetIsochPortCommandIsochPortID (isochPortCommandObjectID,
  792.                                               pFWAVCDriverData->isochPortID);
  793.  
  794.             // Send command to stop port.
  795.             status = FWStopLocalIsochronousPort (isochPortCommandObjectID);
  796.             completionIsPending = true; //zzz what if above call returns an error?
  797.         }
  798.     }
  799.     else
  800.     {
  801.         if (portIsTalker)
  802.         {
  803.             // Set up command object to stop port.
  804.             isochPortCommandObjectID = pFWAVCDriverData->stopIsochPortCommandObjectID;
  805.             fwClientCommandID =
  806.                 pIsochPortControlParams->fwClientInterfaceParams.fwClientCommandID;
  807.             FWSetFWCommandParams (isochPortCommandObjectID,
  808.                                   (FWReferenceID) pFWAVCDriverData->fwDriverID,
  809.                                   0,
  810.                                   FWAVCClientCommandCompletionProc,
  811.                                   (UInt32) fwClientCommandID);
  812.             FWSetIsochPortCommandIsochPortID (isochPortCommandObjectID,
  813.                                               pFWAVCDriverData->isochPortID);
  814.  
  815.             // Send command to stop port.
  816.             status = FWStopLocalIsochronousPort (isochPortCommandObjectID);
  817.             completionIsPending = true; //zzz what if above call returns an error?
  818.         }
  819.         else
  820.         {
  821.             //zzz don't do anything with camera yet.
  822.         }
  823.     }
  824.  
  825.     // Complete command if completion is not pending.
  826.     if (!completionIsPending)
  827.     {
  828.         status = FWClientCommandIsComplete
  829.                     (pIsochPortControlParams->fwClientInterfaceParams.fwClientCommandID,
  830.                      status);
  831.     }
  832.  
  833.     // Return command acceptance.
  834.     //zzz is this the right way?  If we've completed the command, we can accept more.
  835.     *pCommandAcceptance = kFWClientCommandAcceptNoMore;
  836.  
  837.     return (status);
  838. }
  839.  
  840.  
  841. ////////////////////////////////////////////////////////////////////////////////
  842. //
  843. // AVTDriverInterface
  844. //
  845. //   Main driver interface.
  846. //
  847.  
  848. static OSStatus    AVTDriverInterface(
  849.     AVTInterfaceParamsPtr        pAVTInterfaceParams)
  850. {
  851.     UInt32                        interfaceSelector;
  852.     OSStatus                    status = noErr;
  853.  
  854.     // Get some params.
  855.     interfaceSelector = pAVTInterfaceParams->interfaceSelector;
  856.  
  857.     // Main dispatch.
  858.     switch (interfaceSelector)
  859.     {
  860.         case kAVTransportPlay :
  861.  
  862.             status = FWAVCPlay ((AVTPlayParamsPtr) pAVTInterfaceParams);
  863.             break;
  864.  
  865.         case kAVTransportStop :
  866.  
  867.             status = FWAVCStop ((AVTStopParamsPtr) pAVTInterfaceParams);
  868.             break;
  869.  
  870.         case kAVTransportRewind :
  871.  
  872.             status = FWAVCRewind ((AVTRewindParamsPtr) pAVTInterfaceParams);
  873.             break;
  874.  
  875.         case kAVTransportReview :
  876.  
  877.             status = FWAVCReview ((AVTReviewParamsPtr) pAVTInterfaceParams);
  878.             break;
  879.  
  880.         case kAVTransportFastForward :
  881.  
  882.             status = FWAVCFastForward ((AVTFastForwardParamsPtr) pAVTInterfaceParams);
  883.             break;
  884.  
  885.         case kAVTransportFastPlay :
  886.  
  887.             status = FWAVCFastPlay ((AVTFastPlayParamsPtr) pAVTInterfaceParams);
  888.             break;
  889.  
  890.         case kAVTransportWhatchaDoing :
  891.  
  892.             status = FWAVCWhatchaDoing ((AVTWhatchaDoingParamsPtr) pAVTInterfaceParams);
  893.             break;
  894.  
  895.         case kAVTransportPause :
  896.  
  897.             status = FWAVCPause ((AVTPauseParamsPtr) pAVTInterfaceParams);
  898.             break;
  899.  
  900.         case kAVTransportSlow :
  901.  
  902.             status = FWAVCSlow ((AVTSlowParamsPtr) pAVTInterfaceParams);
  903.             break;
  904.  
  905.         case kAVTransportNextFrame :
  906.  
  907.             status = FWAVCNextFrame ((AVTNextFrameParamsPtr) pAVTInterfaceParams);
  908.             break;
  909.  
  910.         case kAVTransportPreviousFrame :
  911.  
  912.             status = FWAVCPreviousFrame ((AVTPreviousFrameParamsPtr) pAVTInterfaceParams);
  913.             break;
  914.  
  915.         case kAVTransportDump :
  916.  
  917.             status = FWAVCDump ((AVTDumpParamsPtr) pAVTInterfaceParams);
  918.             break;
  919.  
  920.         case kAVTransportPlaySnapShot :
  921.  
  922.             status = FWAVCPlaySnapShot ((AVTPlaySnapShotParamsPtr) pAVTInterfaceParams);
  923.             break;
  924.  
  925.         case kAVTransportStopSnapShot :
  926.  
  927.             status = FWAVCStopSnapShot (pAVTInterfaceParams);
  928.             break;
  929.  
  930.         default :
  931.             status = paramErr;
  932.             break;
  933.     }
  934.  
  935.     return (status);
  936. }
  937.  
  938.  
  939. ////////////////////////////////////////////////////////////////////////////////
  940. //
  941. // FWAVCInitialize
  942. //
  943. //   This routine initializes the FireWire AVC transport control driver.  It
  944. // allocates a private data record and registers with the FireWire family.
  945. //
  946.  
  947. static OSStatus    FWAVCInitialize(
  948.     RegEntryIDPtr                pRegEntryID)
  949. {
  950.     FWAVCDriverDataPtr            pFWAVCDriverData = nil;
  951.     FWDriverID                    fwDriverID;
  952.     IsochChannelID                isochChannelID;
  953.     DCLCommandPtr                recordDCLList;
  954.     DCLCommandPtr                *recordUpdateDCLList;
  955.     OSStatus                    status = noErr;
  956.  
  957.     // Allocate our driver data.
  958.     pFWAVCDriverData =
  959.         (FWAVCDriverDataPtr) PoolAllocateResident (sizeof (FWAVCDriverData), true);
  960.     if (pFWAVCDriverData == nil)
  961.     {
  962.         status = memFullErr;
  963.     }
  964.  
  965.     // Register with the FireWire family.
  966.     if (status == noErr)
  967.     {
  968.         status = FWRegisterDriver (pRegEntryID,
  969.                                    &fwDriverID,
  970.                                    &(pFWAVCDriverData->csrUnitID),
  971.                                    (UInt32) pFWAVCDriverData);
  972.  
  973.         if (status == noErr)
  974.             pFWAVCDriverData->fwDriverID = fwDriverID;
  975.     }
  976.  
  977.     // Set initialize isoch port interface proc.
  978.     if (status == noErr)
  979.     {
  980.         status = FWSetFWClientInitIsochPortProc
  981.                     ((FWReferenceID) fwDriverID, FWAVCInitIsochPort);
  982.     }
  983.  
  984.     // Set release isoch port interface proc.
  985.     if (status == noErr)
  986.     {
  987.         status = FWSetFWClientReleaseIsochPortProc
  988.                     ((FWReferenceID) fwDriverID, FWAVCReleaseIsochPort);
  989.     }
  990.  
  991.     // Set start isoch port interface proc.
  992.     if (status == noErr)
  993.     {
  994.         status = FWSetFWClientStartIsochPortProc
  995.                     ((FWReferenceID) fwDriverID, FWAVCStartIsochPort);
  996.     }
  997.  
  998.     // Set stop isoch port interface proc.
  999.     if (status == noErr)
  1000.     {
  1001.         status = FWSetFWClientStopIsochPortProc
  1002.                     ((FWReferenceID) fwDriverID, FWAVCStopIsochPort);
  1003.     }
  1004.  
  1005.     // Get reference to local node.
  1006.     if (status == noErr)
  1007.     {
  1008.         status = FWGetLocalFWReferenceIDFromFWReferenceID
  1009.                     (pFWAVCDriverData->fwDriverID,
  1010.                      &(pFWAVCDriverData->localFWReferenceID));
  1011.     }
  1012.  
  1013.     // Allocate an isochronous channel to play video data.
  1014.     if (status == noErr)
  1015.     {
  1016.         status = FWAllocateIsochronousChannelID
  1017.                     (&isochChannelID, true, 30000000, kFWSpeed100MBit);
  1018.  
  1019.         if (status == noErr)
  1020.             pFWAVCDriverData->playIsochChannelID = isochChannelID;
  1021.     }
  1022.  
  1023.     // Add camera as listening client.
  1024.     if (status == noErr)
  1025.     {
  1026.         status = FWAddIsochronousChannelClient
  1027.                     (pFWAVCDriverData->playIsochChannelID,
  1028.                      pFWAVCDriverData->fwDriverID,
  1029.                      (UInt32) pFWAVCDriverData,
  1030.                      false);
  1031.     }
  1032.  
  1033.     // Add local node as talking client.
  1034.     if (status == noErr)
  1035.     {
  1036.         status = FWAddIsochronousChannelClient
  1037.                     (pFWAVCDriverData->playIsochChannelID,
  1038.                      pFWAVCDriverData->fwDriverID,
  1039.                      (UInt32) pFWAVCDriverData,
  1040.                      true);
  1041.     }
  1042.  
  1043.     // Allocate an isochronous channel to record video data.
  1044.     if (status == noErr)
  1045.     {
  1046.         status = FWAllocateIsochronousChannelID
  1047.                     (&isochChannelID, false, 30000000, kFWSpeed100MBit);
  1048.  
  1049.         if (status == noErr)
  1050.             pFWAVCDriverData->recordIsochChannelID = isochChannelID;
  1051.     }
  1052.  
  1053.     // Add camera as talking client.
  1054.     if (status == noErr)
  1055.     {
  1056.         status = FWAddIsochronousChannelClient
  1057.                     (pFWAVCDriverData->recordIsochChannelID,
  1058.                      pFWAVCDriverData->fwDriverID,
  1059.                      (UInt32) pFWAVCDriverData,
  1060.                      true);
  1061.     }
  1062.  
  1063.     // Add local node as listening client.
  1064.     if (status == noErr)
  1065.     {
  1066.         status = FWAddIsochronousChannelClient
  1067.                     (pFWAVCDriverData->recordIsochChannelID,
  1068.                      pFWAVCDriverData->fwDriverID,
  1069.                      (UInt32) pFWAVCDriverData,
  1070.                      false);
  1071.     }
  1072.  
  1073.     // Create a DCL program for recording.
  1074.     if (status == noErr)
  1075.         status = FWCreateDCLProgram (&(pFWAVCDriverData->recordDCLProgramID));
  1076.  
  1077.     // Create list of DCLs for recording.
  1078.     if (status == noErr)
  1079.     {
  1080.         recordDCLList =
  1081.             (DCLCommandPtr) PoolAllocateResident (kRecordDCLProgramSize, false);
  1082.  
  1083.         if (recordDCLList != nil)
  1084.             pFWAVCDriverData->recordDCLList = recordDCLList;
  1085.         else
  1086.             status = memFullErr;
  1087.     }
  1088.  
  1089.     // Create DCL update list for recording.
  1090.     if (status == noErr)
  1091.     {
  1092.         recordUpdateDCLList = (DCLCommandPtr *)
  1093.             PoolAllocateResident (kRecordNumDCLs * sizeof (DCLCommandPtr), false);
  1094.  
  1095.         if (recordUpdateDCLList != nil)
  1096.             pFWAVCDriverData->recordUpdateDCLList = recordUpdateDCLList;
  1097.         else
  1098.             status = memFullErr;
  1099.     }
  1100.  
  1101.     // Create a DCL program for playing.
  1102.     if (status == noErr)
  1103.         status = FWCreateDCLProgram (&(pFWAVCDriverData->playDCLProgramID));
  1104.  
  1105.     // Allocate FireWire command object for sending isoch channel commands
  1106.     // synchronously.
  1107.     if (status == noErr)
  1108.     {
  1109.         status = FWAllocateIsochChannelCommandObject
  1110.                     (&(pFWAVCDriverData->isochChannelCommandObjectID));
  1111.     }
  1112.  
  1113.     // Allocate FireWire command object for sending stop isoch channel commands
  1114.     // asynchronously.
  1115.     if (status == noErr)
  1116.     {
  1117.         status = FWAllocateIsochChannelCommandObject
  1118.                     (&(pFWAVCDriverData->stopIsochChannelCommandObjectID));
  1119.     }
  1120.  
  1121.     // Allocate FireWire command object for sending start isoch channel commands
  1122.     // asynchronously.
  1123.     if (status == noErr)
  1124.     {
  1125.         status = FWAllocateIsochChannelCommandObject
  1126.                     (&(pFWAVCDriverData->startIsochChannelCommandObjectID));
  1127.     }
  1128.  
  1129.     // Allocate FireWire command object for sending isoch port commands
  1130.     // synchronously.
  1131.     if (status == noErr)
  1132.     {
  1133.         status = FWAllocateIsochPortCommandObject
  1134.                     (&(pFWAVCDriverData->isochPortCommandObjectID));
  1135.     }
  1136.  
  1137.     // Allocate FireWire command object for sending stop isoch port commands
  1138.     // asynchronously.
  1139.     if (status == noErr)
  1140.     {
  1141.         status = FWAllocateIsochPortCommandObject
  1142.                     (&(pFWAVCDriverData->stopIsochPortCommandObjectID));
  1143.     }
  1144.  
  1145.     // Allocate FireWire command object for sending start isoch port commands
  1146.     // asynchronously.
  1147.     if (status == noErr)
  1148.     {
  1149.         status = FWAllocateIsochPortCommandObject
  1150.                     (&(pFWAVCDriverData->startIsochPortCommandObjectID));
  1151.     }
  1152.  
  1153.     // Allocate FireWire command object for sending FCP commands synchronously.
  1154.     if (status == noErr)
  1155.         status = FWAllocateFCPCommandObject (&(pFWAVCDriverData->fcpCommandObjectID));
  1156.  
  1157.     // Allocate FireWire command object for sending FCP commands asynchronously.
  1158.     // With asynchronous commands, we must be careful not to use the command ojbect
  1159.     // more than once at a time.
  1160.     if (status == noErr)
  1161.         status = FWAllocateFCPCommandObject (&(pFWAVCDriverData->asyncFCPCommandObjectID));
  1162.  
  1163.     // Set the maximum packet payload size for camera.
  1164.     if (status == noErr)
  1165.     {
  1166.         status =
  1167.             FWSetMaxPayloadSize ((FWReferenceID) pFWAVCDriverData->fwDriverID,
  1168.                                  512);
  1169.     }
  1170.  
  1171.     // Save our driver data or clean up on error.
  1172.     if (status == noErr)
  1173.     {
  1174.         gpFWAVCDriverData = pFWAVCDriverData;
  1175.     }
  1176.     else
  1177.     {//zzz should use terminate
  1178.         if (pFWAVCDriverData != nil)
  1179.             PoolDeallocate ((Ptr) pFWAVCDriverData);
  1180.     }
  1181.  
  1182.     return (status);
  1183. }
  1184.  
  1185.  
  1186. ////////////////////////////////////////////////////////////////////////////////
  1187. //
  1188. // FWAVCTerminate
  1189. //
  1190. //   This routine terminates the FireWire AVC transport control driver.  It
  1191. // deallocates a private data record and unregisters with the FireWire family.
  1192. //zzz need to do more deallocation.
  1193. //zzz need to stop playing snap shot.
  1194. //
  1195.  
  1196. static OSStatus    FWAVCTerminate(void)
  1197. {
  1198.     OSStatus                    status = noErr;
  1199.  
  1200.     if (gpFWAVCDriverData != nil)
  1201.     {
  1202.         // Unregister with FireWire family.
  1203.         if (gpFWAVCDriverData->fwDriverID != kInvalidFWDriverID)
  1204.             FWUnregisterDriver (gpFWAVCDriverData->fwDriverID);
  1205.  
  1206.         // Deallocate FireWire command object for sending FCP commands asynchronously.
  1207.         if (gpFWAVCDriverData->asyncFCPCommandObjectID != kInvalidFWCommandObjectID)
  1208.             FWDeallocateFWCommandObject (gpFWAVCDriverData->asyncFCPCommandObjectID);
  1209.  
  1210.         // Deallocate FireWire command object for sending FCP commands synchronously.
  1211.         if (gpFWAVCDriverData->fcpCommandObjectID != kInvalidFWCommandObjectID)
  1212.             FWDeallocateFWCommandObject (gpFWAVCDriverData->fcpCommandObjectID);
  1213.  
  1214.         // Deallocate FireWire command object for sending start isoch port commands
  1215.         // asynchronously.
  1216.         if (gpFWAVCDriverData->startIsochPortCommandObjectID != kInvalidFWCommandObjectID)
  1217.             FWDeallocateFWCommandObject (gpFWAVCDriverData->startIsochPortCommandObjectID);
  1218.  
  1219.         // Deallocate FireWire command object for sending stop isoch port commands
  1220.         // asynchronously.
  1221.         if (gpFWAVCDriverData->stopIsochPortCommandObjectID != kInvalidFWCommandObjectID)
  1222.             FWDeallocateFWCommandObject (gpFWAVCDriverData->stopIsochPortCommandObjectID);
  1223.  
  1224.         // Deallocate FireWire command object for sending isoch port commands
  1225.         // synchronously.
  1226.         if (gpFWAVCDriverData->isochPortCommandObjectID != kInvalidFWCommandObjectID)
  1227.             FWDeallocateFWCommandObject (gpFWAVCDriverData->isochPortCommandObjectID);
  1228.  
  1229.         // Deallocate FireWire command object for sending start isoch channel commands
  1230.         // asynchronously.
  1231.         if (gpFWAVCDriverData->startIsochChannelCommandObjectID != kInvalidFWCommandObjectID)
  1232.             FWDeallocateFWCommandObject (gpFWAVCDriverData->startIsochChannelCommandObjectID);
  1233.  
  1234.         // Deallocate FireWire command object for sending stop isoch channel commands
  1235.         // asynchronously.
  1236.         if (gpFWAVCDriverData->stopIsochChannelCommandObjectID != kInvalidFWCommandObjectID)
  1237.             FWDeallocateFWCommandObject (gpFWAVCDriverData->stopIsochChannelCommandObjectID);
  1238.  
  1239.         // Deallocate FireWire command object for sending isoch channel commands
  1240.         // synchronously.
  1241.         if (gpFWAVCDriverData->isochChannelCommandObjectID != kInvalidFWCommandObjectID)
  1242.             FWDeallocateFWCommandObject (gpFWAVCDriverData->isochChannelCommandObjectID);
  1243.  
  1244.         // Deallocate DCL program for playing.
  1245.         if (gpFWAVCDriverData->playDCLProgramID != kInvalidDCLProgramID)
  1246.             FWDisposeDCLProgram (gpFWAVCDriverData->playDCLProgramID);
  1247.  
  1248.         // Deallocate DCL update list for recording.
  1249.         if (gpFWAVCDriverData->recordUpdateDCLList != nil)
  1250.             PoolDeallocate ((Ptr) gpFWAVCDriverData->recordUpdateDCLList);
  1251.  
  1252.         // Deallocate list of DCLs for recording.
  1253.         if (gpFWAVCDriverData->recordDCLList != nil)
  1254.             PoolDeallocate ((Ptr) gpFWAVCDriverData->recordDCLList);
  1255.  
  1256.         // Deallocate DCL program for recording.
  1257.         if (gpFWAVCDriverData->recordDCLProgramID != kInvalidDCLProgramID)
  1258.             FWDisposeDCLProgram (gpFWAVCDriverData->recordDCLProgramID);
  1259.  
  1260.         // Deallocate isochronous channel Id for recording video data.
  1261.         if (gpFWAVCDriverData->recordIsochChannelID != kInvalidIsochChannelID)
  1262.             FWDeallocateIsochronousChannelID (gpFWAVCDriverData->recordIsochChannelID);
  1263.  
  1264.         // Deallocate isochronous channel Id for playing video data.
  1265.         if (gpFWAVCDriverData->playIsochChannelID != kInvalidIsochChannelID)
  1266.             FWDeallocateIsochronousChannelID (gpFWAVCDriverData->playIsochChannelID);
  1267.  
  1268.         // Deallocate our driver data.
  1269.         PoolDeallocate ((Ptr) gpFWAVCDriverData);
  1270.         gpFWAVCDriverData = nil;
  1271.     }
  1272.  
  1273.     return (status);
  1274. }
  1275.  
  1276.  
  1277. ////////////////////////////////////////////////////////////////////////////////
  1278. //
  1279. // FWAVCPlay
  1280. //
  1281. //   This routine starts the camera transport playing.
  1282. //
  1283.  
  1284. static OSStatus    FWAVCPlay(
  1285.     AVTPlayParamsPtr            pAVTPlayParams)
  1286. {
  1287.     FWCommandObjectID            fcpCommandObjectID;
  1288.     UInt32                        fcpPlayFrame[1];
  1289.     OSStatus                    status = noErr;
  1290.  
  1291.     // Set up FCP command to tell camera to start the transport.
  1292.     fcpCommandObjectID = gpFWAVCDriverData->fcpCommandObjectID;
  1293.     fcpPlayFrame[0] = 0x0020C375;
  1294.     FWSetFWCommandParams (fcpCommandObjectID,
  1295.                           (FWReferenceID) gpFWAVCDriverData->fwDriverID,
  1296.                           kFWCommandSyncFlag,
  1297.                           nil,
  1298.                           0);
  1299.     FWSetFCPCommandParams (fcpCommandObjectID,
  1300.                            (Ptr) &(fcpPlayFrame[0]),
  1301.                            4,
  1302.                            (Ptr) &(fcpPlayFrame[0]),
  1303.                            4,
  1304.                            100 * durationMillisecond,
  1305.                            8,
  1306.                            0,
  1307.                            nil);
  1308.  
  1309.     // Send the FCP command.
  1310.     status = FWSendFCPCommand (fcpCommandObjectID);
  1311.  
  1312.     return (status);
  1313. }
  1314.  
  1315.  
  1316. ////////////////////////////////////////////////////////////////////////////////
  1317. //
  1318. // FWAVCRewind
  1319. //
  1320. //   This routine starts the camera transport Rewinding.
  1321. //
  1322.  
  1323. static OSStatus    FWAVCRewind(
  1324.     AVTRewindParamsPtr            pAVTRewindParams)
  1325. {
  1326.     FWCommandObjectID            fcpCommandObjectID;
  1327.     UInt32                        fcpRewindFrame[1];
  1328.     OSStatus                    status = noErr;
  1329.  
  1330.     // Set up FCP command to tell camera to start the transport.
  1331.     fcpCommandObjectID = gpFWAVCDriverData->fcpCommandObjectID;
  1332.     fcpRewindFrame[0] = 0x0020C465;
  1333.     FWSetFWCommandParams (fcpCommandObjectID,
  1334.                           (FWReferenceID) gpFWAVCDriverData->fwDriverID,
  1335.                           kFWCommandSyncFlag,
  1336.                           nil,
  1337.                           0);
  1338.     FWSetFCPCommandParams (fcpCommandObjectID,
  1339.                            (Ptr) &(fcpRewindFrame[0]),
  1340.                            4,
  1341.                            (Ptr) &(fcpRewindFrame[0]),
  1342.                            4,
  1343.                            100 * durationMillisecond,
  1344.                            8,
  1345.                            0,
  1346.                            nil);
  1347.  
  1348.     // Send the FCP command.
  1349.     status = FWSendFCPCommand (fcpCommandObjectID);
  1350.  
  1351.     return (status);
  1352. }
  1353.  
  1354.  
  1355. ////////////////////////////////////////////////////////////////////////////////
  1356. //
  1357. // FWAVCReview
  1358. //
  1359. //   This routine starts the camera transport Reviewing.
  1360. //
  1361.  
  1362. static OSStatus    FWAVCReview(
  1363.     AVTReviewParamsPtr            pAVTReviewParams)
  1364. {
  1365.     FWCommandObjectID            fcpCommandObjectID;
  1366.     UInt32                        fcpReviewFrame[1];
  1367.     OSStatus                    status = noErr;
  1368.  
  1369.     // Set up FCP command to tell camera to start the transport.
  1370.     fcpCommandObjectID = gpFWAVCDriverData->fcpCommandObjectID;
  1371.     fcpReviewFrame[0] = 0x0020c34e;
  1372.     FWSetFWCommandParams (fcpCommandObjectID,
  1373.                           (FWReferenceID) gpFWAVCDriverData->fwDriverID,
  1374.                           kFWCommandSyncFlag,
  1375.                           nil,
  1376.                           0);
  1377.     FWSetFCPCommandParams (fcpCommandObjectID,
  1378.                            (Ptr) &(fcpReviewFrame[0]),
  1379.                            4,
  1380.                            (Ptr) &(fcpReviewFrame[0]),
  1381.                            4,
  1382.                            100 * durationMillisecond,
  1383.                            8,
  1384.                            0,
  1385.                            nil);
  1386.  
  1387.     // Send the FCP command.
  1388.     status = FWSendFCPCommand (fcpCommandObjectID);
  1389.  
  1390.     return (status);
  1391. }
  1392.  
  1393.  
  1394. ////////////////////////////////////////////////////////////////////////////////
  1395. //
  1396. // FWAVCFastForward
  1397. //
  1398. //   This routine starts the camera transport FastForwarding.
  1399. //
  1400.  
  1401. static OSStatus    FWAVCFastForward(
  1402.     AVTFastForwardParamsPtr            pAVTFastForwardParams)
  1403. {
  1404.     FWCommandObjectID            fcpCommandObjectID;
  1405.     UInt32                        fcpFastForwardFrame[1];
  1406.     OSStatus                    status = noErr;
  1407.  
  1408.     // Set up FCP command to tell camera to start the transport.
  1409.     fcpCommandObjectID = gpFWAVCDriverData->fcpCommandObjectID;
  1410.     fcpFastForwardFrame[0] = 0x0020C475;
  1411.     FWSetFWCommandParams (fcpCommandObjectID,
  1412.                           (FWReferenceID) gpFWAVCDriverData->fwDriverID,
  1413.                           kFWCommandSyncFlag,
  1414.                           nil,
  1415.                           0);
  1416.     FWSetFCPCommandParams (fcpCommandObjectID,
  1417.                            (Ptr) &(fcpFastForwardFrame[0]),
  1418.                            4,
  1419.                            (Ptr) &(fcpFastForwardFrame[0]),
  1420.                            4,
  1421.                            100 * durationMillisecond,
  1422.                            8,
  1423.                            0,
  1424.                            nil);
  1425.  
  1426.     // Send the FCP command.
  1427.     status = FWSendFCPCommand (fcpCommandObjectID);
  1428.  
  1429.     return (status);
  1430. }
  1431.  
  1432.  
  1433. ////////////////////////////////////////////////////////////////////////////////
  1434. //
  1435. // FWAVCFastPlay
  1436. //
  1437. //   This routine starts the camera transport FastPlaying.
  1438. //
  1439.  
  1440. static OSStatus    FWAVCFastPlay(
  1441.     AVTFastPlayParamsPtr            pAVTFastPlayParams)
  1442. {
  1443.     FWCommandObjectID            fcpCommandObjectID;
  1444.     UInt32                        fcpFastPlayFrame[1];
  1445.     OSStatus                    status = noErr;
  1446.  
  1447.     // Set up FCP command to tell camera to start the transport.
  1448.     fcpCommandObjectID = gpFWAVCDriverData->fcpCommandObjectID;
  1449.     fcpFastPlayFrame[0] = 0x0020c33e;
  1450.     FWSetFWCommandParams (fcpCommandObjectID,
  1451.                           (FWReferenceID) gpFWAVCDriverData->fwDriverID,
  1452.                           kFWCommandSyncFlag,
  1453.                           nil,
  1454.                           0);
  1455.     FWSetFCPCommandParams (fcpCommandObjectID,
  1456.                            (Ptr) &(fcpFastPlayFrame[0]),
  1457.                            4,
  1458.                            (Ptr) &(fcpFastPlayFrame[0]),
  1459.                            4,
  1460.                            100 * durationMillisecond,
  1461.                            8,
  1462.                            0,
  1463.                            nil);
  1464.  
  1465.     // Send the FCP command.
  1466.     status = FWSendFCPCommand (fcpCommandObjectID);
  1467.  
  1468.     return (status);
  1469. }
  1470.  
  1471.  
  1472. ////////////////////////////////////////////////////////////////////////////////
  1473. //
  1474. // FWAVCPause
  1475. //
  1476. //   This routine starts the camera transport Pauseing.
  1477. //
  1478.  
  1479. static OSStatus    FWAVCPause(
  1480.     AVTPauseParamsPtr            pAVTPauseParams)
  1481. {
  1482.     FWCommandObjectID            fcpCommandObjectID;
  1483.     UInt32                        fcpPauseFrame[1];
  1484.     OSStatus                    status = noErr;
  1485.  
  1486.     // Set up FCP command to tell camera to start the transport.
  1487.     fcpCommandObjectID = gpFWAVCDriverData->fcpCommandObjectID;
  1488.     fcpPauseFrame[0] = 0x0020c37d;
  1489.     FWSetFWCommandParams (fcpCommandObjectID,
  1490.                           (FWReferenceID) gpFWAVCDriverData->fwDriverID,
  1491.                           kFWCommandSyncFlag,
  1492.                           nil,
  1493.                           0);
  1494.     FWSetFCPCommandParams (fcpCommandObjectID,
  1495.                            (Ptr) &(fcpPauseFrame[0]),
  1496.                            4,
  1497.                            (Ptr) &(fcpPauseFrame[0]),
  1498.                            4,
  1499.                            100 * durationMillisecond,
  1500.                            8,
  1501.                            0,
  1502.                            nil);
  1503.  
  1504.     // Send the FCP command.
  1505.     status = FWSendFCPCommand (fcpCommandObjectID);
  1506.  
  1507.     return (status);
  1508. }
  1509.  
  1510.  
  1511. ////////////////////////////////////////////////////////////////////////////////
  1512. //
  1513. // FWAVCSlow
  1514. //
  1515. //   This routine starts the camera transport Slowing.
  1516. //
  1517.  
  1518. static OSStatus    FWAVCSlow(
  1519.     AVTSlowParamsPtr            pAVTSlowParams)
  1520. {
  1521.     FWCommandObjectID            fcpCommandObjectID;
  1522.     UInt32                        fcpSlowFrame[1];
  1523.     OSStatus                    status = noErr;
  1524.  
  1525.     // Set up FCP command to tell camera to start the transport.
  1526.     fcpCommandObjectID = gpFWAVCDriverData->fcpCommandObjectID;
  1527.     fcpSlowFrame[0] = 0x0020c335;
  1528.     FWSetFWCommandParams (fcpCommandObjectID,
  1529.                           (FWReferenceID) gpFWAVCDriverData->fwDriverID,
  1530.                           kFWCommandSyncFlag,
  1531.                           nil,
  1532.                           0);
  1533.     FWSetFCPCommandParams (fcpCommandObjectID,
  1534.                            (Ptr) &(fcpSlowFrame[0]),
  1535.                            4,
  1536.                            (Ptr) &(fcpSlowFrame[0]),
  1537.                            4,
  1538.                            100 * durationMillisecond,
  1539.                            8,
  1540.                            0,
  1541.                            nil);
  1542.  
  1543.     // Send the FCP command.
  1544.     status = FWSendFCPCommand (fcpCommandObjectID);
  1545.  
  1546.     return (status);
  1547. }
  1548.  
  1549.  
  1550. ////////////////////////////////////////////////////////////////////////////////
  1551. //
  1552. // FWAVCNextFrame
  1553. //
  1554. //   This routine starts the camera transport NextFrameing.
  1555. //
  1556.  
  1557. static OSStatus    FWAVCNextFrame(
  1558.     AVTNextFrameParamsPtr            pAVTNextFrameParams)
  1559. {
  1560.     FWCommandObjectID            fcpCommandObjectID;
  1561.     UInt32                        fcpNextFrameFrame[1];
  1562.     OSStatus                    status = noErr;
  1563.  
  1564.     // Set up FCP command to tell camera to start the transport.
  1565.     fcpCommandObjectID = gpFWAVCDriverData->fcpCommandObjectID;
  1566.     fcpNextFrameFrame[0] = 0x0020c330;
  1567.     FWSetFWCommandParams (fcpCommandObjectID,
  1568.                           (FWReferenceID) gpFWAVCDriverData->fwDriverID,
  1569.                           kFWCommandSyncFlag,
  1570.                           nil,
  1571.                           0);
  1572.     FWSetFCPCommandParams (fcpCommandObjectID,
  1573.                            (Ptr) &(fcpNextFrameFrame[0]),
  1574.                            4,
  1575.                            (Ptr) &(fcpNextFrameFrame[0]),
  1576.                            4,
  1577.                            100 * durationMillisecond,
  1578.                            8,
  1579.                            0,
  1580.                            nil);
  1581.  
  1582.     // Send the FCP command.
  1583.     status = FWSendFCPCommand (fcpCommandObjectID);
  1584.  
  1585.     return (status);
  1586. }
  1587.  
  1588. ////////////////////////////////////////////////////////////////////////////////
  1589. //
  1590. // FWAVCPreviousFrame
  1591. //
  1592. //   This routine PreviousFrames the camera transport.
  1593. //
  1594.  
  1595. static OSStatus    FWAVCPreviousFrame(
  1596.     AVTPreviousFrameParamsPtr            pAVTPreviousFrameParams)
  1597. {
  1598.     FWCommandObjectID            fcpCommandObjectID;
  1599.     UInt32                        fcpPreviousFrameFrame[1];
  1600.     OSStatus                    status = noErr;
  1601.  
  1602.     // Set up FCP command params to tell camera to PreviousFrame the transport.
  1603.     fcpCommandObjectID = gpFWAVCDriverData->fcpCommandObjectID;
  1604.     fcpPreviousFrameFrame[0] = 0x0020c340;
  1605.     FWSetFWCommandParams (fcpCommandObjectID,
  1606.                           (FWReferenceID) gpFWAVCDriverData->fwDriverID,
  1607.                           kFWCommandSyncFlag,
  1608.                           nil,
  1609.                           0);
  1610.     FWSetFCPCommandParams (fcpCommandObjectID,
  1611.                            (Ptr) &(fcpPreviousFrameFrame[0]),
  1612.                            4,
  1613.                            (Ptr) &(fcpPreviousFrameFrame[0]),
  1614.                            4,
  1615.                            100 * durationMillisecond,
  1616.                            8,
  1617.                            0,
  1618.                            nil);
  1619.  
  1620.     // Send the FCP command.
  1621.     status = FWSendFCPCommand (fcpCommandObjectID);
  1622.  
  1623.     return (status);
  1624. }
  1625.  
  1626.  
  1627.  
  1628. ////////////////////////////////////////////////////////////////////////////////
  1629. //
  1630. // FWAVCStop
  1631. //
  1632. //   This routine stops the camera transport.
  1633. //
  1634.  
  1635. static OSStatus    FWAVCStop(
  1636.     AVTStopParamsPtr            pAVTStopParams)
  1637. {
  1638.     FWCommandObjectID            fcpCommandObjectID;
  1639.     UInt32                        fcpStopFrame[1];
  1640.     OSStatus                    status = noErr;
  1641.  
  1642.     // Set up FCP command params to tell camera to stop the transport.
  1643.     fcpCommandObjectID = gpFWAVCDriverData->fcpCommandObjectID;
  1644.     fcpStopFrame[0] = 0x0020C460;
  1645.     FWSetFWCommandParams (fcpCommandObjectID,
  1646.                           (FWReferenceID) gpFWAVCDriverData->fwDriverID,
  1647.                           kFWCommandSyncFlag,
  1648.                           nil,
  1649.                           0);
  1650.     FWSetFCPCommandParams (fcpCommandObjectID,
  1651.                            (Ptr) &(fcpStopFrame[0]),
  1652.                            4,
  1653.                            (Ptr) &(fcpStopFrame[0]),
  1654.                            4,
  1655.                            100 * durationMillisecond,
  1656.                            8,
  1657.                            0,
  1658.                            nil);
  1659.  
  1660.     // Send the FCP command.
  1661.     status = FWSendFCPCommand (fcpCommandObjectID);
  1662.  
  1663.     return (status);
  1664. }
  1665.  
  1666.  
  1667.  
  1668. static OSStatus FWAVCWhatchaDoing(
  1669.     AVTWhatchaDoingParamsPtr             pAVTWhatchaDoingParams)
  1670. {
  1671.     OSStatus                    status = noErr;
  1672. //    FWFCPCommandParams            fwFCPCommandParams;
  1673.     UInt32                        fcpWhatchaDoingFrame[1], temp;
  1674.     FWCommandObjectID            fcpCommandObjectID;
  1675.  
  1676.     // Set up FCP command params to tell camera to stop the transport.
  1677.     fcpCommandObjectID = gpFWAVCDriverData->fcpCommandObjectID;
  1678.  
  1679.     // Set up FCP command params to tell camera to start WhatchaDoinging.
  1680.     fcpWhatchaDoingFrame[0] = 0x0120d07f;
  1681.  
  1682.     FWSetFWCommandParams (fcpCommandObjectID,
  1683.                           (FWReferenceID) gpFWAVCDriverData->fwDriverID,
  1684.                           kFWCommandSyncFlag,
  1685.                           nil,
  1686.                           0);
  1687.     FWSetFCPCommandParams (fcpCommandObjectID,
  1688.                            (Ptr) &(fcpWhatchaDoingFrame[0]),
  1689.                            4,
  1690.                            (Ptr) &(fcpWhatchaDoingFrame[0]),
  1691.                            4,
  1692.                            100 * durationMillisecond,
  1693.                            8,
  1694.                            0,
  1695.                            nil);
  1696.  
  1697.  
  1698.     status = FWSendFCPCommand (fcpCommandObjectID);
  1699.     temp = fcpWhatchaDoingFrame[0];
  1700.     
  1701.     temp = (temp & 0x0000ffff);
  1702.  
  1703.     // Figure out what return number means to the user
  1704.     if (!status) {
  1705.         switch (temp) {
  1706.             case PLAY:
  1707.                 pAVTWhatchaDoingParams->what = kAVTransportPlay;
  1708.                 break;
  1709.             case SLOW:
  1710.                 pAVTWhatchaDoingParams->what = kAVTransportSlow;
  1711.                 break;
  1712.             case PLAYBACK:
  1713.                 pAVTWhatchaDoingParams->what = kAVTransportPlayBack;
  1714.                 break;
  1715.             case FASTPLAY:
  1716.                 pAVTWhatchaDoingParams->what = kAVTransportFastPlay;
  1717.                 break;
  1718.             case REVIEW:
  1719.                 pAVTWhatchaDoingParams->what = kAVTransportReview;
  1720.                 break;
  1721.             case PAUSE:
  1722.                 pAVTWhatchaDoingParams->what = kAVTransportPause;
  1723.                 break;
  1724.             default:
  1725.                 pAVTWhatchaDoingParams->what = 0;
  1726.         }
  1727.     }
  1728.  
  1729.     return (status);
  1730. }
  1731.  
  1732.  
  1733. ////////////////////////////////////////////////////////////////////////////////
  1734. //
  1735. // FWAVCDump
  1736. //
  1737. //   This routine gets a video dump from the camera.
  1738. //
  1739.  
  1740. static OSStatus    FWAVCDump(
  1741.     AVTDumpParamsPtr            pAVTDumpParams)
  1742. {
  1743.     FWCommandObjectID            isochChannelCommandObjectID;
  1744.     FWAVCDVPingPongDataPtr        pFWAVCDVPingPongData;
  1745.     Ptr                            pDCLCommand;
  1746.     DCLLabelPtr                    pStartDCLLabel;
  1747.     DCLTransferPacketPtr        pDCLTransferPacket;
  1748.     DCLCallProcPtr                pDCLPingPongProc;
  1749.     DCLJumpPtr                    pDCLPingPongLoop;
  1750.     DCLUpdateDCLListPtr            pDCLUpdateDCLList;
  1751.     DCLCommandPtr                *updateDCLList,
  1752.                                 *pingPongUpdateDCLList;
  1753.     UInt32                        updateListSize;
  1754.     Ptr                            pingPongBuffer = nil;
  1755.     UInt32                        size;
  1756.     volatile UInt32                *pBufferOffset;
  1757.     UInt32                        pingPongNum,
  1758.                                 packetNum;
  1759.     OSStatus                    status = noErr;
  1760.  
  1761.     // Save pointer to params.
  1762.     gpFWAVCDriverData->pAVTDumpParams = pAVTDumpParams;
  1763.  
  1764.     // Create ping pong buffer.
  1765.     //zzz should allocate in initialization routine.
  1766.     pingPongBuffer = PoolAllocateResident (kPingPongBufferSize, false);
  1767.  
  1768.     // Get pointer to start of DCL commands and update list.
  1769.     pDCLCommand = (Ptr) gpFWAVCDriverData->recordDCLList;
  1770.     updateDCLList = gpFWAVCDriverData->recordUpdateDCLList;
  1771.  
  1772.     // Create label for start of loop.
  1773.     pStartDCLLabel = (DCLLabelPtr) pDCLCommand;
  1774.     pDCLCommand += sizeof (DCLLabel);
  1775.     pStartDCLLabel->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
  1776.     pStartDCLLabel->opcode = kDCLLabelOp;
  1777.  
  1778.     // Create 2 ping pong buffer lists of 10 packets each.
  1779.     for (pingPongNum = 0; pingPongNum < kNumPingPongs; pingPongNum++)
  1780.     {
  1781.         // Create ping pong data record and fill it in.
  1782.         pFWAVCDVPingPongData = (FWAVCDVPingPongDataPtr)
  1783.             PoolAllocateResident (sizeof (FWAVCDVPingPongData), true);
  1784.         pFWAVCDVPingPongData->pFWAVCDriverData = gpFWAVCDriverData;
  1785.         pFWAVCDVPingPongData->pFirstDCLCommand = (DCLCommandPtr) pDCLCommand;
  1786.  
  1787.         // Create transfer DCL for each packet.
  1788.         pingPongUpdateDCLList = updateDCLList;
  1789.         updateListSize = 0;
  1790.         for (packetNum = 0; packetNum < kNumPacketsPerPingPong; packetNum++)
  1791.         {
  1792.             // Receive one packet up to kReceiveDVPacketSize bytes.
  1793.             pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  1794.             pDCLCommand += sizeof (DCLTransferPacket);
  1795.             pDCLTransferPacket->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
  1796.             pDCLTransferPacket->opcode = kDCLReceivePacketStartOp;
  1797.             pDCLTransferPacket->buffer = pingPongBuffer;
  1798.             pDCLTransferPacket->size = kReceiveDVPacketSize;
  1799.  
  1800.             *updateDCLList++ = (DCLCommandPtr) pDCLTransferPacket;
  1801.             updateListSize++;
  1802.             pingPongBuffer += kReceiveDVPacketSize;
  1803.         }
  1804.  
  1805.         // Create update DCL list.
  1806.         pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand;
  1807.         pDCLCommand += sizeof (DCLUpdateDCLList);
  1808.         pDCLUpdateDCLList->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
  1809.         pDCLUpdateDCLList->opcode = kDCLUpdateDCLListOp;
  1810.         pDCLUpdateDCLList->dclCommandList = pingPongUpdateDCLList;
  1811.         pDCLUpdateDCLList->numDCLCommands = updateListSize;
  1812.  
  1813.         // Call the ping pong proc.
  1814.         pDCLPingPongProc = (DCLCallProcPtr) pDCLCommand;
  1815.         pDCLCommand += sizeof (DCLCallProc);
  1816.         pDCLPingPongProc->pNextDCLCommand = (DCLCommandPtr) pDCLCommand;
  1817.         pDCLPingPongProc->opcode = kDCLCallProcOp;
  1818.         pDCLPingPongProc->proc = FWAVCDVPingPong;
  1819.         pDCLPingPongProc->procData = (UInt32) pFWAVCDVPingPongData;
  1820.     }
  1821.  
  1822.     // Loop to start of ping pong.
  1823.     pDCLPingPongLoop = (DCLJumpPtr) pDCLCommand;
  1824.     pDCLPingPongLoop->pNextDCLCommand = nil;
  1825.     pDCLPingPongLoop->opcode = kDCLJumpOp;
  1826.     pDCLPingPongLoop->pJumpDCLLabel = pStartDCLLabel;
  1827.  
  1828.     // Set start of DCL program.
  1829.     if (status == noErr)
  1830.     {
  1831.         status = FWSetDCLProgramStart (gpFWAVCDriverData->recordDCLProgramID,
  1832.                                        gpFWAVCDriverData->recordDCLList);
  1833.     }
  1834.  
  1835.     // Initialize the isochrounous channel.
  1836.     if (status == noErr)
  1837.     {
  1838.         isochChannelCommandObjectID = gpFWAVCDriverData->isochChannelCommandObjectID;
  1839.         FWSetFWCommandParams (isochChannelCommandObjectID,
  1840.                               kInvalidFWReferenceID,
  1841.                               kFWCommandSyncFlag,
  1842.                               nil,
  1843.                               0);
  1844.         FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  1845.                                                 gpFWAVCDriverData->recordIsochChannelID);
  1846.  
  1847.         status = FWInitializeIsochronousChannel (isochChannelCommandObjectID);
  1848.         if (status == noErr)
  1849.             gpFWAVCDriverData->channelInitialized = true;
  1850.     }
  1851.  
  1852.     // Start the isochronous channel for recording.
  1853.     if (status == noErr)
  1854.     {
  1855.         isochChannelCommandObjectID = gpFWAVCDriverData->isochChannelCommandObjectID;
  1856.         FWSetFWCommandParams (isochChannelCommandObjectID,
  1857.                               kInvalidFWReferenceID,
  1858.                               kFWCommandSyncFlag,
  1859.                               nil,
  1860.                               0);
  1861.         FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  1862.                                                 gpFWAVCDriverData->recordIsochChannelID);
  1863.  
  1864.         status = FWStartIsochronousChannel (isochChannelCommandObjectID);
  1865.     }
  1866.  
  1867.     // Wait for buffer to fill.
  1868.     if (status == noErr)
  1869.     {
  1870.         size = pAVTDumpParams->dumpBufferSize;
  1871.         pBufferOffset = &(pAVTDumpParams->dumpBufferOffset);
  1872.         while ((*pBufferOffset) < size)
  1873.         {
  1874.         }
  1875.     }
  1876.  
  1877.     // Release isochronous channel.
  1878.     if (gpFWAVCDriverData->channelInitialized)
  1879.     {
  1880.         isochChannelCommandObjectID = gpFWAVCDriverData->isochChannelCommandObjectID;
  1881.         FWSetFWCommandParams (isochChannelCommandObjectID,
  1882.                               kInvalidFWReferenceID,
  1883.                               kFWCommandSyncFlag,
  1884.                               nil,
  1885.                               0);
  1886.         FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  1887.                                                 gpFWAVCDriverData->recordIsochChannelID);
  1888.  
  1889.         FWStopIsochronousChannel (isochChannelCommandObjectID);
  1890.  
  1891.         FWSetFWCommandParams (isochChannelCommandObjectID,
  1892.                               kInvalidFWReferenceID,
  1893.                               kFWCommandSyncFlag,
  1894.                               nil,
  1895.                               0);
  1896.         FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  1897.                                                 gpFWAVCDriverData->recordIsochChannelID);
  1898.  
  1899.         FWReleaseIsochronousChannel (isochChannelCommandObjectID);
  1900.  
  1901.         gpFWAVCDriverData->channelInitialized = false;
  1902.     }
  1903.  
  1904.     return (status);
  1905. }
  1906.  
  1907.  
  1908. ////////////////////////////////////////////////////////////////////////////////
  1909. //
  1910. // FWAVCPlaySnapShot
  1911. //
  1912. //   This routine plays a snapshot video stream.
  1913. //zzz need error checking.
  1914. //
  1915.  
  1916. static OSStatus    FWAVCPlaySnapShot(
  1917.     AVTPlaySnapShotParamsPtr    pAVTPlaySnapShotParams)
  1918. {
  1919.     FWCommandObjectID            isochChannelCommandObjectID;
  1920.     DCLCommandPoolPtr            pDCLCommandPool;
  1921.     DCLCommandPtr                pDCLCommand;
  1922.     DCLCommandPtr                pFirstBufferGroupDCLCommand;
  1923.     DCLLabelPtr                    pUnderrunDCLLabel,
  1924.                                 pLoopDCLLabel,
  1925.                                 pBufferGroupDCLLabel,
  1926.                                 pDCLLabel;
  1927.     DCLTransferPacketPtr        pDCLTransferPacket;
  1928.     DCLCallProcPtr                pDCLCallProc;
  1929.     DCLSetTagSyncBitsPtr        pDCLSetTagSyncBits;
  1930.     DCLJumpPtr                    pDCLJump,
  1931.                                 pBufferGroupDCLJump;
  1932.     DCLLabelPtr                    pBufferGroupSkipEmptyPacketDCLLabel;
  1933.     DCLUpdateDCLListPtr            pDCLUpdateDCLList;
  1934.     DCLTimeStampPtr                pDCLTimeStamp;
  1935.  
  1936.     FWAVCPlayBufferGroupDataPtr    pFWAVCPlayBufferGroupData;
  1937.     UInt32                        matchValue[2] = { 0x00780000, 0x80000000 },
  1938.                                 matchMask[2] = { 0xF0FFFF00, 0xFFFF0000 },
  1939.                                 matchIndex;
  1940.     UInt32                        *pBuffer,
  1941.                                 *pCompactBuffer,
  1942.                                 bufferValue;
  1943.     UInt32                        *pTransmitBuffer;
  1944.     UInt32                        snapShotBufferSize,
  1945.                                 goodSnapShotBufferSize;
  1946.     UInt32                        i,
  1947.                                 bufferGroupNum,
  1948.                                 dataPacketNum,
  1949.                                 numPackets;
  1950.     UInt32                        numEmptyPacketsPerPlayBufferGroup;
  1951.     UInt32                        transmitBuffersSize;
  1952.     UInt32                        emptyPacketNumerator;
  1953.     float                        A, B, C, d, n;
  1954.     OSStatus                    status = noErr;
  1955.  
  1956.     // Process the buffer.
  1957.     pBuffer = (UInt32 *) pAVTPlaySnapShotParams->snapShotBuffer;
  1958.     snapShotBufferSize = pAVTPlaySnapShotParams->snapShotBufferSize;
  1959.     matchIndex = 0;
  1960.     for (i = 0; i < snapShotBufferSize; i++)
  1961.     {
  1962.         // Read next buffer value.
  1963.         bufferValue = *pBuffer++;
  1964.  
  1965.         // Check for match.
  1966.         if ((bufferValue & matchMask[matchIndex]) == matchValue[matchIndex])
  1967.             matchIndex++;
  1968.         else
  1969.             matchIndex = 0;
  1970.  
  1971.         // Check for start of frame if we've matched enough.
  1972.         if (matchIndex == 2)
  1973.         {
  1974.             if (((bufferValue & 0x00000C00) != 0x00000C00) &&
  1975.                 (!((pBuffer[0] & matchMask[0]) == matchValue[0])))
  1976.                 break;
  1977.             else
  1978.                 matchIndex = 0;
  1979.         }
  1980.     }
  1981.     pBuffer -= 2;
  1982.  
  1983.     // Check if we have enough data left.
  1984.     goodSnapShotBufferSize =
  1985.         snapShotBufferSize -
  1986.         (((UInt32) pBuffer) -
  1987.          ((UInt32) pAVTPlaySnapShotParams->snapShotBuffer));
  1988.     if (goodSnapShotBufferSize < kMinDVFrameSize)
  1989.         status = -1;
  1990.  
  1991.     // Compact data.
  1992.     if (status == noErr)
  1993.     {
  1994.         pCompactBuffer = (UInt32 *) pAVTPlaySnapShotParams->snapShotBuffer;
  1995.         for (dataPacketNum = 0; dataPacketNum < kNumDVPacketsPerFrame; dataPacketNum++)
  1996.         {
  1997.             if ((pBuffer[2] & matchMask[0]) != matchValue[0])
  1998.             {
  1999.                 BlockCopy (pBuffer + 2, pCompactBuffer, 480);
  2000.                 pBuffer += 122;
  2001.                 pCompactBuffer += 120;
  2002.             }
  2003.  
  2004.             while ((pBuffer[2] & matchMask[0]) == matchValue[0])
  2005.                 pBuffer += 2;
  2006.         }
  2007.  
  2008.         gpFWAVCDriverData->imageBuffer = pAVTPlaySnapShotParams->snapShotBuffer;
  2009.     }
  2010.  
  2011.     // Compute nominal frame period cycle time.
  2012.     if (status == noErr)
  2013.     {
  2014.         gpFWAVCDriverData->nominalFrameCycleTime =
  2015.             FWAVCConvertFractionalSecondsToCycleTime
  2016.                 (kPlayFramePeriodNumerator, kPlayFramePeriodDenominator);
  2017.     }
  2018.  
  2019.     // Compute the number of data packets per empty packet.
  2020.     // If the frame rate is expressed as n/d, the number of data packets per buffer group
  2021.     // expressed as A, and the number of data packets per frame as C, then the number of
  2022.     // empty packets per buffer group B should be
  2023.     //
  2024.     // B = int (8000*d/n*A/C - A + 1)
  2025.     //
  2026.     // in order to ensure that the frame rate may be maintained by periodically reducing
  2027.     // the number of empty packets in a buffer group by 1.
  2028.     //
  2029.     if (status == noErr)
  2030.     {
  2031.         A = (float) kNumDataPacketsPerPlayBufferGroup;
  2032.         C = (float) kNumDataPacketsPerDVFrame;
  2033.         n = (float) kPlayFrameRateNumerator;
  2034.         d = (float) kPlayFrameRateDenominator;
  2035.         B = 8000.0*d/n*A/C - A + 1;
  2036.         numEmptyPacketsPerPlayBufferGroup = (UInt32) B;
  2037.     }
  2038.  
  2039.     // Allocate transmit buffers.
  2040.     if (status == noErr)
  2041.     {
  2042.         if (gpFWAVCDriverData->transmitBuffers == nil)
  2043.         {
  2044.             // Compute size.
  2045.             transmitBuffersSize =
  2046.                 kNumDataPacketsPerPlayBufferGroup * (kDVPacketCIPSize + kDVPacketDataSize); 
  2047.             transmitBuffersSize +=
  2048.                 numEmptyPacketsPerPlayBufferGroup * kDVPacketCIPSize;
  2049.             transmitBuffersSize *= kNumPlayBufferGroups;
  2050.  
  2051.             // Allocate.
  2052.             gpFWAVCDriverData->transmitBuffers =
  2053.                 PoolAllocateResident (transmitBuffersSize, false);
  2054.             if (gpFWAVCDriverData->transmitBuffers == nil)
  2055.                 status = memFullErr;
  2056.         }
  2057.         pTransmitBuffer = (UInt32 *) gpFWAVCDriverData->transmitBuffers;
  2058.     }
  2059.  
  2060.     // Allocate DCL command pool.
  2061.     if (status == noErr)
  2062.     {
  2063.         pDCLCommandPool = FWAVCAllocateDCLCommandPool ();
  2064.         if (pDCLCommandPool != nil)
  2065.             gpFWAVCDriverData->pPlayDCLCommandPool = pDCLCommandPool;
  2066.         else
  2067.             status = memFullErr;
  2068.     }
  2069.  
  2070.     // Fill in buffers.
  2071.     if (status == noErr)
  2072.     {
  2073.         // Initialize total packet count.
  2074.         gpFWAVCDriverData->totalPlayPackets = 0;
  2075.  
  2076.         // Create label for start of loop.
  2077.         pLoopDCLLabel = (DCLLabelPtr)
  2078.             FWAVCAllocateDCLCommand (pDCLCommandPool, sizeof (DCLLabel));
  2079.         pDCLCommand = (DCLCommandPtr) pLoopDCLLabel;
  2080.         gpFWAVCDriverData->playDCLList = pDCLCommand;
  2081.         pLoopDCLLabel->opcode = kDCLLabelOp;
  2082.  
  2083.         // Set isoch packet tag bits.
  2084.         pDCLSetTagSyncBits = (DCLSetTagSyncBitsPtr)
  2085.             FWAVCAllocateDCLCommand (pDCLCommandPool, sizeof (DCLSetTagSyncBits));
  2086.         pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLSetTagSyncBits;
  2087.         pDCLCommand = (DCLCommandPtr) pDCLSetTagSyncBits;
  2088.         pDCLSetTagSyncBits->opcode = kDCLSetTagSyncBitsOp;
  2089.         pDCLSetTagSyncBits->tagBits = 1;
  2090.         pDCLSetTagSyncBits->syncBits = 0;
  2091.  
  2092.         for (bufferGroupNum = 0; bufferGroupNum < kNumPlayBufferGroups; bufferGroupNum++)
  2093.         {
  2094.             // Allocate a buffer group data record.
  2095.             pFWAVCPlayBufferGroupData = FWAVCAllocatePlayBufferGroup (gpFWAVCDriverData);
  2096.             
  2097.             // Initialize for loop.
  2098.             dataPacketNum = 0;
  2099.             numPackets = 0;
  2100.             emptyPacketNumerator = 0;
  2101.             pFirstBufferGroupDCLCommand = nil;
  2102.             pBufferGroupSkipEmptyPacketDCLLabel = nil;
  2103.  
  2104.             while (dataPacketNum < kNumDataPacketsPerPlayBufferGroup)
  2105.             {
  2106.                 // Send a packet.
  2107.                 // CIP header.
  2108.                 pDCLTransferPacket = (DCLTransferPacketPtr)
  2109.                     FWAVCAllocateDCLCommand (pDCLCommandPool, sizeof (DCLTransferPacket));
  2110.                 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLTransferPacket;
  2111.                 pDCLCommand = (DCLCommandPtr) pDCLTransferPacket;
  2112.                 pDCLTransferPacket->opcode = kDCLSendPacketStartOp;
  2113.                 pDCLTransferPacket->buffer = (Ptr) pTransmitBuffer;
  2114.                 pDCLTransferPacket->size = 8;
  2115.  
  2116.                 pTransmitBuffer += 2;
  2117.  
  2118.                 // Save first data packet DCL command.
  2119.                 if (pFirstBufferGroupDCLCommand == nil)
  2120.                     pFirstBufferGroupDCLCommand = (DCLCommandPtr) pDCLCommand;
  2121.  
  2122.                 // Payload.
  2123.                 pDCLTransferPacket = (DCLTransferPacketPtr)
  2124.                     FWAVCAllocateDCLCommand (pDCLCommandPool, sizeof (DCLTransferPacket));
  2125.                 pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLTransferPacket;
  2126.                 pDCLCommand = (DCLCommandPtr) pDCLTransferPacket;
  2127.                 pDCLTransferPacket->opcode = kDCLSendPacketOp;
  2128.                 pDCLTransferPacket->buffer = (Ptr) pTransmitBuffer;
  2129.                 pDCLTransferPacket->size = 480;
  2130.  
  2131.                 pTransmitBuffer += 120;
  2132.                 dataPacketNum++;
  2133.                 numPackets++;
  2134.                 emptyPacketNumerator += numEmptyPacketsPerPlayBufferGroup;
  2135.  
  2136.                 if (emptyPacketNumerator >= kNumDataPacketsPerPlayBufferGroup)
  2137.                 {
  2138.                     // Add skip jump if this is the first empty packet in the buffer group.
  2139.                     if (pBufferGroupSkipEmptyPacketDCLLabel == nil)
  2140.                     {
  2141.                         pDCLJump = (DCLJumpPtr)
  2142.                             FWAVCAllocateDCLCommand (pDCLCommandPool, sizeof (DCLJump));
  2143.                         pFWAVCPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLJump =
  2144.                             pDCLJump;
  2145.                         pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLJump;
  2146.                         pDCLCommand = (DCLCommandPtr) pDCLJump;
  2147.                         pDCLJump->opcode = kDCLJumpOp | kFWDCLOpDynamicFlag;
  2148.  
  2149.                         pDCLLabel = (DCLLabelPtr)
  2150.                             FWAVCAllocateDCLCommand (pDCLCommandPool, sizeof (DCLLabel));
  2151.                         pFWAVCPlayBufferGroupData->pBufferGroupDontSkipEmptyPacketDCLLabel =
  2152.                             pDCLLabel;
  2153.                         pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLLabel;
  2154.                         pDCLCommand = (DCLCommandPtr) pDCLLabel;
  2155.                         pDCLLabel->opcode = kDCLLabelOp;
  2156.  
  2157.                         pDCLJump->pJumpDCLLabel = pDCLLabel;
  2158.                     }
  2159.  
  2160.                     // Send a packet.
  2161.                     // Just CIP header.
  2162.                     pDCLTransferPacket = (DCLTransferPacketPtr)
  2163.                         FWAVCAllocateDCLCommand (pDCLCommandPool,
  2164.                                                  sizeof (DCLTransferPacket));
  2165.                     pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLTransferPacket;
  2166.                     pDCLCommand = (DCLCommandPtr) pDCLTransferPacket;
  2167.                     pDCLTransferPacket->opcode = kDCLSendPacketStartOp;
  2168.                     pDCLTransferPacket->buffer = (Ptr) pTransmitBuffer;
  2169.                     pDCLTransferPacket->size = 8;
  2170.  
  2171.                     pTransmitBuffer += 2;
  2172.                     numPackets++;
  2173.                     emptyPacketNumerator -= kNumDataPacketsPerPlayBufferGroup;
  2174.  
  2175.                     // Add skip jump label if this is the first empty packet in the
  2176.                     // buffer group.
  2177.                     if (pBufferGroupSkipEmptyPacketDCLLabel == nil)
  2178.                     {
  2179.                         // Add skip label.
  2180.                         pDCLLabel = (DCLLabelPtr)
  2181.                             FWAVCAllocateDCLCommand (pDCLCommandPool, sizeof (DCLLabel));
  2182.                         pBufferGroupSkipEmptyPacketDCLLabel = pDCLLabel;
  2183.                         pFWAVCPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLLabel =
  2184.                             pBufferGroupSkipEmptyPacketDCLLabel;
  2185.                         pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLLabel;
  2186.                         pDCLCommand = (DCLCommandPtr) pDCLLabel;
  2187.                         pDCLLabel->opcode = kDCLLabelOp;
  2188.                     }
  2189.                 }
  2190.             }
  2191.  
  2192.             // Save number of packets in this buffer group, DCL update list size, and last
  2193.             // DCL command.
  2194.             pFWAVCPlayBufferGroupData->numPackets = numPackets;
  2195.             pFWAVCPlayBufferGroupData->pFirstBufferGroupDCLCommand =
  2196.                 pFirstBufferGroupDCLCommand;
  2197.             pFWAVCPlayBufferGroupData->pLastBufferGroupDCLCommand =
  2198.                 (DCLCommandPtr) pDCLCommand;
  2199.  
  2200.             // Create buffer group update list.
  2201.             FWAVCCreatePlayBufferGroupUpdateList (pFWAVCPlayBufferGroupData);
  2202.  
  2203.             // Update total packet count.
  2204.             gpFWAVCDriverData->totalPlayPackets += numPackets;
  2205.  
  2206.             // Create end of buffer group jump.
  2207.             pBufferGroupDCLJump = (DCLJumpPtr)
  2208.                 FWAVCAllocateDCLCommand (pDCLCommandPool, sizeof (DCLJump));
  2209.             pFWAVCPlayBufferGroupData->pEndOfBufferGroupDCLJump = pBufferGroupDCLJump;
  2210.             pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pBufferGroupDCLJump;
  2211.             pDCLCommand = (DCLCommandPtr) pBufferGroupDCLJump;
  2212.             pBufferGroupDCLJump->opcode = kDCLJumpOp | kFWDCLOpDynamicFlag;
  2213.  
  2214.             // Create label for end of buffer group.
  2215.             pBufferGroupDCLLabel = (DCLLabelPtr)
  2216.                 FWAVCAllocateDCLCommand (pDCLCommandPool, sizeof (DCLLabel));
  2217.             pFWAVCPlayBufferGroupData->pEndOfBufferGroupDCLLabel = pBufferGroupDCLLabel;
  2218.             pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pBufferGroupDCLLabel;
  2219.             pDCLCommand = (DCLCommandPtr) pBufferGroupDCLLabel;
  2220.             pBufferGroupDCLLabel->opcode = kDCLLabelOp;
  2221.  
  2222.             // Set end of buffer group jump to jump to end of buffer group.
  2223.             pBufferGroupDCLJump->pJumpDCLLabel = pBufferGroupDCLLabel;
  2224.  
  2225.             // Get time stamp at end of buffer group.
  2226.             pDCLTimeStamp = (DCLTimeStampPtr)
  2227.                 FWAVCAllocateDCLCommand (pDCLCommandPool, sizeof (DCLTimeStamp));
  2228.             pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLTimeStamp;
  2229.             pDCLCommand = (DCLCommandPtr) pDCLTimeStamp;
  2230.             pDCLTimeStamp->opcode = kDCLTimeStampOp;
  2231.             pFWAVCPlayBufferGroupData->pBufferGroupDCLTimeStamp = pDCLTimeStamp;
  2232.             pFWAVCPlayBufferGroupData->timeStampUpdateDCLList =
  2233.                 (DCLCommandPtr) pDCLTimeStamp;
  2234.  
  2235.             // Create update DCL list to update time stamp.
  2236.             pDCLUpdateDCLList = (DCLUpdateDCLListPtr)
  2237.                 FWAVCAllocateDCLCommand (pDCLCommandPool, sizeof (DCLUpdateDCLList));
  2238.             pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLUpdateDCLList;
  2239.             pDCLCommand = (DCLCommandPtr) pDCLUpdateDCLList;
  2240.             pDCLUpdateDCLList->opcode = kDCLUpdateDCLListOp;
  2241.             pDCLUpdateDCLList->dclCommandList =
  2242.                 &(pFWAVCPlayBufferGroupData->timeStampUpdateDCLList);
  2243.             pDCLUpdateDCLList->numDCLCommands = 1;
  2244.  
  2245.             // Call a proc at end of buffer group.
  2246.             pDCLCallProc = (DCLCallProcPtr)
  2247.                 FWAVCAllocateDCLCommand (pDCLCommandPool, sizeof (DCLCallProc));
  2248.             pFWAVCPlayBufferGroupData->pBufferGroupDCLCallProc = pDCLCallProc;
  2249.             pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLCallProc;
  2250.             pDCLCommand = (DCLCommandPtr) pDCLCallProc;
  2251.             pDCLCallProc->opcode = kDCLCallProcOp;
  2252.             pDCLCallProc->proc = FWAVCHandleDVSend;
  2253.             pDCLCallProc->procData = (UInt32) pFWAVCPlayBufferGroupData;
  2254.  
  2255.             // Create update DCL list to update buffers.
  2256.             pDCLUpdateDCLList = (DCLUpdateDCLListPtr)
  2257.                 FWAVCAllocateDCLCommand (pDCLCommandPool, sizeof (DCLUpdateDCLList));
  2258.             pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLUpdateDCLList;
  2259.             pDCLCommand = (DCLCommandPtr) pDCLUpdateDCLList;
  2260.             pDCLUpdateDCLList->opcode = kDCLUpdateDCLListOp;
  2261.             pDCLUpdateDCLList->dclCommandList =
  2262.                 pFWAVCPlayBufferGroupData->bufferGroupUpdateDCLList;
  2263.             pDCLUpdateDCLList->numDCLCommands = pFWAVCPlayBufferGroupData->updateListSize;
  2264.         }
  2265.  
  2266.         // Loop to first buffer group.
  2267.         pDCLJump = (DCLJumpPtr)
  2268.             FWAVCAllocateDCLCommand (pDCLCommandPool, sizeof (DCLJump));
  2269.         pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLJump;
  2270.         pDCLCommand = (DCLCommandPtr) pDCLJump;
  2271.         pDCLJump->opcode = kDCLJumpOp | kFWDCLOpDynamicFlag;
  2272.         pDCLJump->pJumpDCLLabel = pLoopDCLLabel;
  2273.  
  2274.         // Create label for underrun.
  2275.         pUnderrunDCLLabel = (DCLLabelPtr)
  2276.             FWAVCAllocateDCLCommand (pDCLCommandPool, sizeof (DCLLabel));
  2277.         gpFWAVCDriverData->pUnderrunDCLLabel = pUnderrunDCLLabel;
  2278.         pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pUnderrunDCLLabel;
  2279.         pDCLCommand = (DCLCommandPtr) pUnderrunDCLLabel;
  2280.         pUnderrunDCLLabel->opcode = kDCLLabelOp;
  2281.  
  2282.         // Set last buffer group's jump DCL to jump to underrun.
  2283.         pBufferGroupDCLJump->pJumpDCLLabel = pUnderrunDCLLabel;
  2284.  
  2285.         // Call underrun proc.
  2286.         // This is the last command.
  2287.         pDCLCallProc = (DCLCallProcPtr)
  2288.             FWAVCAllocateDCLCommand (pDCLCommandPool, sizeof (DCLCallProc));
  2289.         pDCLCommand->pNextDCLCommand = (DCLCommandPtr) pDCLCallProc;
  2290.         pDCLCallProc->pNextDCLCommand = nil;
  2291.         pDCLCallProc->opcode = kDCLCallProcOp;
  2292.         pDCLCallProc->proc = FWAVCHandleDVSendUnderrun;
  2293.         pDCLCallProc->procData = (UInt32) gpFWAVCDriverData;
  2294.  
  2295.         // Initialize number of active play packets.
  2296.         gpFWAVCDriverData->activePlayPackets = gpFWAVCDriverData->totalPlayPackets;
  2297.     }
  2298.  
  2299.     // Set up all of the buffer groups.
  2300.     if (status == noErr)
  2301.     {
  2302.         gpFWAVCDriverData->nextSYT = kPlaySYTDelay;
  2303.         pFWAVCPlayBufferGroupData = gpFWAVCDriverData->pFWAVCPlayBufferGroupDataList;
  2304.         for (bufferGroupNum = 0; bufferGroupNum < kNumPlayBufferGroups; bufferGroupNum++)
  2305.         {
  2306.             FWAVCUpdateDVSendBuffers
  2307.                 ((DCLCommandPtr) pFWAVCPlayBufferGroupData->pBufferGroupDCLCallProc);
  2308.             pFWAVCPlayBufferGroupData =
  2309.                 pFWAVCPlayBufferGroupData->pNextFWAVCPlayBufferGroupData;
  2310.         }
  2311.     }
  2312.  
  2313.     // Set start of DCL program.
  2314.     if (status == noErr)
  2315.     {
  2316.         status = FWSetDCLProgramStart (gpFWAVCDriverData->playDCLProgramID,
  2317.                                        gpFWAVCDriverData->playDCLList);
  2318.     }
  2319.  
  2320.     // Set start event for DCL program
  2321.     if (status == noErr)
  2322.     {
  2323.         status = FWSetDCLProgramStartEvent (gpFWAVCDriverData->playDCLProgramID,
  2324.                                             kFWDCLCycleEvent,
  2325.                                             0,
  2326.                                             BitRange (12, 15));
  2327.     }
  2328.  
  2329.     // Initialize the isochrounous channel.
  2330.     if (status == noErr)
  2331.     {
  2332.         isochChannelCommandObjectID = gpFWAVCDriverData->isochChannelCommandObjectID;
  2333.         FWSetFWCommandParams (isochChannelCommandObjectID,
  2334.                               kInvalidFWReferenceID,
  2335.                               kFWCommandSyncFlag,
  2336.                               nil,
  2337.                               0);
  2338.         FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  2339.                                                 gpFWAVCDriverData->playIsochChannelID);
  2340.  
  2341.         status = FWInitializeIsochronousChannel (isochChannelCommandObjectID);
  2342.         if (status == noErr)
  2343.             gpFWAVCDriverData->playSnapShotChannelInitialized = true;
  2344.     }
  2345.  
  2346.     // Start the isochronous channel for playing.
  2347.     if (status == noErr)
  2348.     {
  2349.         isochChannelCommandObjectID = gpFWAVCDriverData->isochChannelCommandObjectID;
  2350.         FWSetFWCommandParams (isochChannelCommandObjectID,
  2351.                               kInvalidFWReferenceID,
  2352.                               kFWCommandSyncFlag,
  2353.                               nil,
  2354.                               0);
  2355.         FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  2356.                                                 gpFWAVCDriverData->playIsochChannelID);
  2357.  
  2358.         status = FWStartIsochronousChannel (isochChannelCommandObjectID);
  2359.     }
  2360.  
  2361.     return (status);
  2362. }
  2363.  
  2364.  
  2365. ////////////////////////////////////////////////////////////////////////////////
  2366. //
  2367. // FWAVCStopSnapShot
  2368. //
  2369. //   This routine stops a snapshot video stream.
  2370. //
  2371.  
  2372. static OSStatus    FWAVCStopSnapShot(
  2373.     AVTInterfaceParamsPtr        pAVTInterfaceParams)
  2374. {
  2375.     FWCommandObjectID            isochChannelCommandObjectID;
  2376.     FWAVCPlayBufferGroupDataPtr    pFWAVCPlayBufferGroupData,
  2377.                                 pNextFWAVCPlayBufferGroupData;
  2378.     UInt32                        bufferGroupNum;
  2379.     OSStatus                    status = noErr;
  2380.  
  2381.     // Stop the snap shot.
  2382.     if (gpFWAVCDriverData->playSnapShotChannelInitialized)
  2383.     {
  2384.         isochChannelCommandObjectID = gpFWAVCDriverData->isochChannelCommandObjectID;
  2385.         FWSetFWCommandParams (isochChannelCommandObjectID,
  2386.                               kInvalidFWReferenceID,
  2387.                               kFWCommandSyncFlag,
  2388.                               nil,
  2389.                               0);
  2390.         FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  2391.                                                 gpFWAVCDriverData->playIsochChannelID);
  2392.  
  2393.         FWStopIsochronousChannel (isochChannelCommandObjectID);
  2394.  
  2395.         isochChannelCommandObjectID = gpFWAVCDriverData->isochChannelCommandObjectID;
  2396.         FWSetFWCommandParams (isochChannelCommandObjectID,
  2397.                               kInvalidFWReferenceID,
  2398.                               kFWCommandSyncFlag,
  2399.                               nil,
  2400.                               0);
  2401.         FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  2402.                                                 gpFWAVCDriverData->playIsochChannelID);
  2403.  
  2404.         FWReleaseIsochronousChannel (isochChannelCommandObjectID);
  2405.  
  2406.         // Deallocate play buffer group data records.
  2407.         pFWAVCPlayBufferGroupData = gpFWAVCDriverData->pFWAVCPlayBufferGroupDataList;
  2408.         if (pFWAVCPlayBufferGroupData != nil)
  2409.         {
  2410.             for (bufferGroupNum = 0;
  2411.                  bufferGroupNum < kNumPlayBufferGroups;
  2412.                  bufferGroupNum++)
  2413.             {
  2414.                 pNextFWAVCPlayBufferGroupData =
  2415.                     pFWAVCPlayBufferGroupData->pNextFWAVCPlayBufferGroupData;
  2416.                 FWAVCDeallocatePlayBufferGroup (pFWAVCPlayBufferGroupData);
  2417.                 pFWAVCPlayBufferGroupData = pNextFWAVCPlayBufferGroupData;
  2418.             }
  2419.         }
  2420.         gpFWAVCDriverData->pFWAVCPlayBufferGroupDataList = nil;
  2421.  
  2422.         FWAVCDeallocateDCLCommandPool (gpFWAVCDriverData->pPlayDCLCommandPool);
  2423.         gpFWAVCDriverData->pPlayDCLCommandPool = nil;
  2424.  
  2425.         PoolDeallocate (gpFWAVCDriverData->transmitBuffers);
  2426.         gpFWAVCDriverData->transmitBuffers = nil;
  2427.  
  2428.         gpFWAVCDriverData->playSnapShotChannelInitialized = false;
  2429.     }
  2430.  
  2431.     return (status);
  2432. }
  2433.  
  2434.  
  2435. ////////////////////////////////////////////////////////////////////////////////
  2436. //
  2437. // FWAVCDVPingPong
  2438. //
  2439. //   This routine handles ping pong DV dumping.
  2440. //
  2441.  
  2442. static void    FWAVCDVPingPong(
  2443.     DCLCommandPtr                pDCLCommandPtr)
  2444. {
  2445.     FWAVCDVPingPongDataPtr        pFWAVCDVPingPongData;
  2446.     FWAVCDriverDataPtr            pFWAVCDriverData;
  2447.     AVTDumpParamsPtr            pAVTDumpParams;
  2448.     DCLCallProcPtr                pDCLCallProc;
  2449.     DCLCommandPtr                pCurrentDCLCommand;
  2450.     DCLTransferPacketPtr        pDCLTransferPacket;
  2451.     UInt32                        transferSize;
  2452.     Ptr                            packetBuffer;
  2453.     UInt32                        packetHeader;
  2454.     UInt32                        packetSize;
  2455.     Ptr                            dumpBuffer;
  2456.     UInt32                        dumpBufferLeft;
  2457.     UInt32                        dumpBufferOffset;
  2458.     UInt32                        packetNum;
  2459.  
  2460.     // Recast DCL command.
  2461.     pDCLCallProc = (DCLCallProcPtr) pDCLCommandPtr;
  2462.  
  2463.     // Get ping pong data.
  2464.     pFWAVCDVPingPongData = (FWAVCDVPingPongDataPtr) pDCLCallProc->procData;
  2465.  
  2466.     // Get info from ping pong data.
  2467.     pFWAVCDriverData = pFWAVCDVPingPongData->pFWAVCDriverData;
  2468.     pCurrentDCLCommand = pFWAVCDVPingPongData->pFirstDCLCommand;
  2469.     pAVTDumpParams = pFWAVCDriverData->pAVTDumpParams;
  2470.     dumpBufferOffset = pAVTDumpParams->dumpBufferOffset;
  2471.     dumpBuffer = pAVTDumpParams->dumpBuffer;
  2472.     dumpBufferLeft = pAVTDumpParams->dumpBufferSize - dumpBufferOffset;
  2473.  
  2474.     // Copy data from packets.
  2475.     for (packetNum = 0;
  2476.          ((packetNum < kNumPacketsPerPingPong) && (dumpBufferLeft > 0));
  2477.          packetNum++)
  2478.     {
  2479.         // Compute size of transfer.
  2480.         pDCLTransferPacket = (DCLTransferPacketPtr) pCurrentDCLCommand;
  2481.         packetBuffer = pDCLTransferPacket->buffer;
  2482.         packetHeader = *((UInt32 *) packetBuffer);
  2483.         packetBuffer += 4;
  2484.         packetSize = (packetHeader & kFWIsochDataLength) >> kFWIsochDataLengthPhase;
  2485.         if (packetSize < dumpBufferLeft)
  2486.             transferSize = packetSize;
  2487.         else
  2488.             transferSize = dumpBufferLeft;
  2489.  
  2490.         // Do transfer.
  2491.         BlockCopy (packetBuffer, dumpBuffer + dumpBufferOffset, transferSize);
  2492.  
  2493.         // Update for next packet.
  2494.         pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand;
  2495.         dumpBufferLeft -= transferSize;
  2496.         dumpBufferOffset += transferSize;
  2497.     }
  2498.  
  2499.     // Update dump buffer params.
  2500.     pAVTDumpParams->dumpBufferOffset = dumpBufferOffset;
  2501. }
  2502.  
  2503.  
  2504. ////////////////////////////////////////////////////////////////////////////////
  2505. //
  2506. // FWAVCHandleDVSend
  2507. //
  2508. //   This routine handles isochronous sending of DV data.
  2509. //
  2510.  
  2511. static void    FWAVCHandleDVSend(
  2512.     DCLCommandPtr                pDCLCommandPtr)
  2513. {
  2514.     DCLCallProcPtr                pDCLCallProc;
  2515.     DCLTimeStampPtr                pDCLTimeStamp;
  2516.     FWAVCPlayBufferGroupDataPtr    pFWAVCPlayBufferGroupData,
  2517.                                 pPrevFWAVCPlayBufferGroupData;
  2518.     FWAVCDriverDataPtr            pFWAVCDriverData;
  2519.     UInt32                        nominalFrameCycleTime;
  2520.     UInt32                        fractionalFrameCycleCount,
  2521.                                 fractionalFrameCycleOffset;
  2522.     SInt32                        timeDrift;
  2523.     UInt32                        projectedTimeStamp,
  2524.                                 projectedSYT;
  2525.  
  2526.     // Recast pDCLCommandPtr.
  2527.     pDCLCallProc = (DCLCallProcPtr) pDCLCommandPtr;
  2528.  
  2529.     // Get data for buffer group and driver data.
  2530.     pFWAVCPlayBufferGroupData = (FWAVCPlayBufferGroupDataPtr) pDCLCallProc->procData;
  2531.     pFWAVCDriverData = pFWAVCPlayBufferGroupData->pFWAVCDriverData;
  2532.     nominalFrameCycleTime = pFWAVCDriverData->nominalFrameCycleTime;
  2533.  
  2534.     // Undo skipping empty packet if we're currently skipping a packet.
  2535.     if (pFWAVCPlayBufferGroupData->skippingEmptyPacket)
  2536.     {
  2537.         FWModifyDCLJump
  2538.             (pFWAVCDriverData->playDCLProgramID,
  2539.              pFWAVCPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLJump,
  2540.              pFWAVCPlayBufferGroupData->pBufferGroupDontSkipEmptyPacketDCLLabel);
  2541.         pFWAVCDriverData->activePlayPackets++;
  2542.         pFWAVCPlayBufferGroupData->skippingEmptyPacket = false;
  2543.     }
  2544.  
  2545.     // Get data for previous buffer group.
  2546.     pPrevFWAVCPlayBufferGroupData =
  2547.         pFWAVCPlayBufferGroupData->pPrevFWAVCPlayBufferGroupData;
  2548.  
  2549.     // Compute time drift.
  2550.  
  2551.     // Compute the projected time stamp value for the first packet of the current
  2552.     // buffer group the next time this proc is called for the current buffer group.
  2553.  
  2554.     // Start at time stamp of first packet in next buffer group to be sent.
  2555.     pDCLTimeStamp = pFWAVCPlayBufferGroupData->pBufferGroupDCLTimeStamp;
  2556.     projectedTimeStamp = pDCLTimeStamp->timeStamp + 1;
  2557.  
  2558.     // Add the total number of cycles for all active buffer group packets.
  2559.     projectedTimeStamp += pFWAVCDriverData->activePlayPackets << 12;
  2560.  
  2561.     // Subtract the number of cycles for all packets in the current buffer group.
  2562.     projectedTimeStamp -= pFWAVCPlayBufferGroupData->numPackets << 12;
  2563.  
  2564.     // Compute the projected SYT value for the first packet of the current buffer group
  2565.     // the next time this proc is called for the current buffer group.
  2566.  
  2567.     // Start with the SYT value to use for the first packet of the next frame.
  2568.     projectedSYT = pFWAVCDriverData->nextSYT;
  2569.  
  2570.     // Subtract the SYT offset between frames.
  2571.     projectedSYT =
  2572.         FWAVCSubtractCycleTimeFromCycleTime (projectedSYT, nominalFrameCycleTime);
  2573.  
  2574.     // Add the fraction of the SYT offset between the start of the frame and the
  2575.     // first data packet for the current buffer group.
  2576.     fractionalFrameCycleOffset =
  2577.         ((nominalFrameCycleTime & 0x0FFF) * pFWAVCDriverData->nextDataPacketNum) /
  2578.         kNumDataPacketsPerDVFrame;
  2579.  
  2580.     fractionalFrameCycleCount =
  2581.         ((nominalFrameCycleTime & 0x01FFF000) * pFWAVCDriverData->nextDataPacketNum) /
  2582.         kNumDataPacketsPerDVFrame;
  2583.     fractionalFrameCycleCount =
  2584.         (fractionalFrameCycleCount & 0x01FFF000) +
  2585.         (((fractionalFrameCycleCount & 0x0FFF) * 3072) / 4096);
  2586.  
  2587.     projectedSYT = FWAVCAddCycleTimeToCycleTime (projectedSYT, fractionalFrameCycleOffset);
  2588.     projectedSYT = FWAVCAddCycleTimeToCycleTime (projectedSYT, fractionalFrameCycleCount);
  2589.  
  2590.     // The time drift is the difference between the projected time stamp and SYT.
  2591.     // We must convert the time drift to cycles.
  2592.     timeDrift = (projectedTimeStamp >> 12) + kPlaySYTDelay - (projectedSYT >> 12);
  2593.     timeDrift &= 0x0F;
  2594.  
  2595.     // Skip an empty packet if we're drifting.
  2596.     // Only consider positive drifting.
  2597.     if ((timeDrift > 0) && (timeDrift < 8))
  2598.     {
  2599.         FWModifyDCLJump (pFWAVCDriverData->playDCLProgramID,
  2600.                          pFWAVCPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLJump,
  2601.                          pFWAVCPlayBufferGroupData->pBufferGroupSkipEmptyPacketDCLLabel);
  2602.         pFWAVCDriverData->activePlayPackets--;
  2603.         pFWAVCPlayBufferGroupData->skippingEmptyPacket = true;
  2604.     }
  2605.  
  2606.     FWAVCUpdateDVSendBuffers (pDCLCommandPtr);
  2607.  
  2608.     // Update DCL jumps to call underrun proc after this buffer group.
  2609.     //zzz check errors.
  2610.     FWModifyDCLJump (pFWAVCDriverData->playDCLProgramID,
  2611.                      pFWAVCPlayBufferGroupData->pEndOfBufferGroupDCLJump,
  2612.                      pFWAVCDriverData->pUnderrunDCLLabel);
  2613.     FWModifyDCLJump (pFWAVCDriverData->playDCLProgramID,
  2614.                      pPrevFWAVCPlayBufferGroupData->pEndOfBufferGroupDCLJump,
  2615.                      pPrevFWAVCPlayBufferGroupData->pEndOfBufferGroupDCLLabel);
  2616. }
  2617.  
  2618.  
  2619. ////////////////////////////////////////////////////////////////////////////////
  2620. //
  2621. // FWAVCUpdateDVSendBuffers
  2622. //
  2623. //   This routine updates the buffers for sending DV data.
  2624. //
  2625.  
  2626. static void    FWAVCUpdateDVSendBuffers(
  2627.     DCLCommandPtr                pDCLCommandPtr)
  2628. {
  2629.     DCLCommandPtr                pCurrentDCLCommand;
  2630.     DCLCallProcPtr                pDCLCallProc;
  2631.     DCLTransferPacketPtr        pDCLTransferPacket;
  2632.     FWAVCPlayBufferGroupDataPtr    pFWAVCPlayBufferGroupData,
  2633.                                 pPrevFWAVCPlayBufferGroupData;
  2634.     FWAVCDriverDataPtr            pFWAVCDriverData;
  2635.     UInt32                        localNodeID;
  2636.     UInt32                        generation;
  2637.     UInt32                        nominalFrameCycleTime;
  2638.     UInt32                        syt;
  2639.     UInt32                        *pBuffer,
  2640.                                 *pImageBuffer;
  2641.     UInt32                        packetNum,
  2642.                                 dataPacketNum,
  2643.                                 numPackets;
  2644.     UInt32                        dbc;
  2645.  
  2646.     // Recast pDCLCommandPtr.
  2647.     pDCLCallProc = (DCLCallProcPtr) pDCLCommandPtr;
  2648.  
  2649.     // Get data for buffer group.
  2650.     pFWAVCPlayBufferGroupData = (FWAVCPlayBufferGroupDataPtr) pDCLCallProc->procData;
  2651.  
  2652.     // Get driver data and first DCL command.
  2653.     pFWAVCDriverData = pFWAVCPlayBufferGroupData->pFWAVCDriverData;
  2654.     pCurrentDCLCommand = pFWAVCPlayBufferGroupData->pFirstBufferGroupDCLCommand;
  2655.     nominalFrameCycleTime = pFWAVCDriverData->nominalFrameCycleTime;
  2656.  
  2657.     // Get data for previous buffer group.
  2658.     pPrevFWAVCPlayBufferGroupData =
  2659.         pFWAVCPlayBufferGroupData->pPrevFWAVCPlayBufferGroupData;
  2660.     syt = pFWAVCDriverData->nextSYT;
  2661.     dbc = pFWAVCDriverData->nextDBC;
  2662.     dataPacketNum = pFWAVCDriverData->nextDataPacketNum;
  2663.  
  2664.     // Get local node ID.
  2665.     FWGetNodeID (pFWAVCDriverData->localFWReferenceID, &localNodeID, &generation);
  2666.  
  2667.     // Get first send packet command for this buffer group.
  2668.     while (pCurrentDCLCommand->opcode != kDCLSendPacketStartOp)
  2669.         pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand;
  2670.     pDCLTransferPacket = (DCLTransferPacketPtr) pCurrentDCLCommand;
  2671.  
  2672.     // Update the packet buffers.
  2673.     numPackets = pFWAVCPlayBufferGroupData->numPackets;
  2674.     pImageBuffer = (UInt32 *) (pFWAVCDriverData->imageBuffer + 480*dataPacketNum);
  2675.     for (packetNum = 0; packetNum < numPackets; packetNum++)
  2676.     {
  2677.         // Set up packet header.
  2678.         pBuffer = (UInt32 *) pDCLTransferPacket->buffer;
  2679.         pBuffer[0] = 0x00780000 | (localNodeID << 24) | (dbc & 0xFF);
  2680.         pBuffer[1] = 0x8000FFFF;
  2681.  
  2682.         // See if this is a data packet.
  2683.         pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand;
  2684.         if (pCurrentDCLCommand != nil)
  2685.         {
  2686.             if (pCurrentDCLCommand->opcode == kDCLSendPacketOp)
  2687.             {
  2688.                 // Set SYT field if this is the first data packet in the frame.
  2689.                 if (dataPacketNum == 0)
  2690.                 {
  2691.                     pBuffer[1] = 0x80000000 | (syt & 0xFFFF);
  2692.  
  2693.                     // Increment next syt by one frame period.
  2694.                     pFWAVCDriverData->sytNumerator += kPlayFramePeriodNumerator;
  2695.                     if (pFWAVCDriverData->sytNumerator > kPlayFramePeriodDenominator)
  2696.                         pFWAVCDriverData->sytNumerator -= kPlayFramePeriodDenominator;
  2697.                     syt = FWAVCConvertFractionalSecondsToCycleTime
  2698.                             (pFWAVCDriverData->sytNumerator, kPlayFramePeriodDenominator);
  2699.                 }
  2700.         
  2701.                 // Copy data into packet.
  2702.                 pDCLTransferPacket = (DCLTransferPacketPtr) pCurrentDCLCommand;
  2703.                 BlockCopy (pImageBuffer, pDCLTransferPacket->buffer, 480);
  2704.                 pImageBuffer += 120;
  2705.                 dbc++;
  2706.                 dataPacketNum++;
  2707.                 if (dataPacketNum == kNumDataPacketsPerDVFrame)
  2708.                 {
  2709.                     pImageBuffer = (UInt32 *) pFWAVCDriverData->imageBuffer;
  2710.                     dataPacketNum = 0;
  2711.                 }
  2712.             }
  2713.         }
  2714.  
  2715.         // Find next send packet start command.
  2716.         while (pCurrentDCLCommand != nil)
  2717.         {
  2718.             if (pCurrentDCLCommand->opcode != kDCLSendPacketStartOp)
  2719.                 pCurrentDCLCommand = pCurrentDCLCommand->pNextDCLCommand;
  2720.             else
  2721.                 break;
  2722.         }
  2723.         pDCLTransferPacket = (DCLTransferPacketPtr) pCurrentDCLCommand;
  2724.     }
  2725.     pFWAVCDriverData->nextSYT = syt;
  2726.     pFWAVCDriverData->nextDBC = dbc;
  2727.     pFWAVCDriverData->nextDataPacketNum = dataPacketNum;
  2728.  
  2729.     // Call to update DCL's if we need to.  We have to do this on underrun because the update
  2730.     // DCL command won't be run to reflect the changes we've made here.
  2731.     if (pFWAVCPlayBufferGroupData->needsUpdate)
  2732.     {
  2733.         FWUpdateDCLList (pFWAVCDriverData->playDCLProgramID,
  2734.                          pFWAVCPlayBufferGroupData->bufferGroupUpdateDCLList,
  2735.                          pFWAVCPlayBufferGroupData->updateListSize);
  2736.         pFWAVCPlayBufferGroupData->needsUpdate = false;
  2737.     }
  2738. }
  2739.  
  2740.  
  2741. ////////////////////////////////////////////////////////////////////////////////
  2742. //
  2743. // FWAVCHandleDVSendUnderrun
  2744. //
  2745. //   This routine handles underruns for sending DV data.
  2746. //
  2747.  
  2748. static void    FWAVCHandleDVSendUnderrun(
  2749.     DCLCommandPtr                pDCLCommandPtr)
  2750. {
  2751.     DCLCallProcPtr                pDCLCallProc;
  2752.     FWAVCDriverDataPtr            pFWAVCDriverData;
  2753.     FWCommandObjectID            isochChannelCommandObjectID;
  2754.  
  2755.     // Recast pDCLCommandPtr.
  2756.     pDCLCallProc = (DCLCallProcPtr) pDCLCommandPtr;
  2757.  
  2758.     // Get driver data.
  2759.     pFWAVCDriverData = (FWAVCDriverDataPtr) pDCLCallProc->procData;
  2760.  
  2761.     // Set up params for stopping isochronous channel.
  2762.     isochChannelCommandObjectID = pFWAVCDriverData->stopIsochChannelCommandObjectID;
  2763.     FWSetFWCommandParams (isochChannelCommandObjectID,
  2764.                           kInvalidFWReferenceID,
  2765.                           0,
  2766.                           FWAVCHandleDVSendUnderrunStopIsochronousChannelCompletionProc,
  2767.                           (UInt32) pDCLCallProc);
  2768.     FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  2769.                                             pFWAVCDriverData->playIsochChannelID);
  2770.  
  2771.     // Stop the isochronous channel.
  2772.     FWStopIsochronousChannel (isochChannelCommandObjectID);
  2773. }
  2774.  
  2775.  
  2776. ////////////////////////////////////////////////////////////////////////////////
  2777. //
  2778. // FWAVCHandleDVSendUnderrunStopIsochronousChannelCompletionProc
  2779. //
  2780. //   This routine handles underruns for sending DV data.
  2781. //
  2782.  
  2783. static void    FWAVCHandleDVSendUnderrunStopIsochronousChannelCompletionProc(
  2784.     FWCommandObjectID            fwCommandObjectID,
  2785.     OSStatus                    commandStatus,
  2786.     UInt32                        completionProcData)
  2787. {
  2788.     DCLCallProcPtr                pDCLCallProc;
  2789.     FWAVCDriverDataPtr            pFWAVCDriverData;
  2790.     FWAVCPlayBufferGroupDataPtr    pFWAVCPlayBufferGroupData;
  2791.     FWCommandObjectID            isochChannelCommandObjectID;
  2792.     UInt32                        bufferGroupNum;
  2793.  
  2794.     // Get DCL call proc data.
  2795.     pDCLCallProc = (DCLCallProcPtr) completionProcData;
  2796.  
  2797.     // Get driver data.
  2798.     pFWAVCDriverData = (FWAVCDriverDataPtr) pDCLCallProc->procData;
  2799.  
  2800.     // Reset next SYT, dbc, and data packet num.
  2801.     pFWAVCDriverData->nextSYT = kPlaySYTDelay;
  2802.     pFWAVCDriverData->nextDBC = 0;
  2803.     pFWAVCDriverData->nextDataPacketNum = 0;
  2804.  
  2805.     // Reset up all of the buffer groups.
  2806.     pFWAVCPlayBufferGroupData = pFWAVCDriverData->pFWAVCPlayBufferGroupDataList;
  2807.     for (bufferGroupNum = 0; bufferGroupNum < kNumPlayBufferGroups; bufferGroupNum++)
  2808.     {
  2809.         // Update buffer group buffers.
  2810.         pFWAVCPlayBufferGroupData->needsUpdate = true;
  2811.         FWAVCUpdateDVSendBuffers
  2812.             ((DCLCommandPtr) pFWAVCPlayBufferGroupData->pBufferGroupDCLCallProc);
  2813.  
  2814.         // Update buffer group jump DCL.
  2815.         if (bufferGroupNum < (kNumPlayBufferGroups - 1))
  2816.         {
  2817.             FWModifyDCLJump (pFWAVCDriverData->playDCLProgramID,
  2818.                              pFWAVCPlayBufferGroupData->pEndOfBufferGroupDCLJump,
  2819.                              pFWAVCPlayBufferGroupData->pEndOfBufferGroupDCLLabel);
  2820.         }
  2821.         else
  2822.         {
  2823.             FWModifyDCLJump (pFWAVCDriverData->playDCLProgramID,
  2824.                              pFWAVCPlayBufferGroupData->pEndOfBufferGroupDCLJump,
  2825.                              pFWAVCDriverData->pUnderrunDCLLabel);
  2826.         }
  2827.  
  2828.         pFWAVCPlayBufferGroupData =
  2829.             pFWAVCPlayBufferGroupData->pNextFWAVCPlayBufferGroupData;
  2830.     }
  2831.  
  2832.     // Set up params for starting isochronous channel.
  2833.     isochChannelCommandObjectID = pFWAVCDriverData->startIsochChannelCommandObjectID;
  2834.     FWSetFWCommandParams (isochChannelCommandObjectID,
  2835.                           kInvalidFWReferenceID,
  2836.                           0,
  2837.                           nil,
  2838.                           0);
  2839.     FWSetIsochChannelCommandIsochChannelID (isochChannelCommandObjectID,
  2840.                                             pFWAVCDriverData->playIsochChannelID);
  2841.  
  2842.     // Restart the isochronous channel.
  2843.     FWStartIsochronousChannel (isochChannelCommandObjectID);
  2844. }
  2845.  
  2846.  
  2847. ////////////////////////////////////////////////////////////////////////////////
  2848. //
  2849. // FWAVCClientCommandCompletionProc
  2850. //
  2851. //   This routine does generic completion of FireWire client commands that
  2852. // make asynchronous FireWire service calls.
  2853. //
  2854.  
  2855. static void    FWAVCClientCommandCompletionProc(
  2856.     FWCommandObjectID            fwCommandObjectID,
  2857.     OSStatus                    commandStatus,
  2858.     UInt32                        completionProcData)
  2859. {
  2860.     FWClientCommandIsComplete ((FWClientCommandID) completionProcData,  commandStatus);
  2861. }
  2862.  
  2863.  
  2864. ////////////////////////////////////////////////////////////////////////////////
  2865. //
  2866. // FWAVCAllocatePlayBufferGroup
  2867. //
  2868. //   This routine allocates a buffer group for playing.
  2869. //
  2870.  
  2871. static FWAVCPlayBufferGroupDataPtr    FWAVCAllocatePlayBufferGroup(
  2872.     FWAVCDriverDataPtr            pFWAVCDriverData)
  2873. {
  2874.     FWAVCPlayBufferGroupDataPtr    pFWAVCPlayBufferGroupData = nil,
  2875.                                 pPrevFWAVCPlayBufferGroupData,
  2876.                                 pNextFWAVCPlayBufferGroupData;
  2877.     OSStatus                    status = noErr;
  2878.  
  2879.     // Allocate buffer group data record.
  2880.     pFWAVCPlayBufferGroupData = (FWAVCPlayBufferGroupDataPtr)
  2881.         PoolAllocateResident (sizeof (FWAVCPlayBufferGroupData), true);
  2882.     if (pFWAVCPlayBufferGroupData != nil)
  2883.         pFWAVCPlayBufferGroupData->pFWAVCDriverData = pFWAVCDriverData;
  2884.     else
  2885.         status = memFullErr;
  2886.  
  2887.     // Insert buffer group data record into list.
  2888.     if (status == noErr)
  2889.     {
  2890.         pNextFWAVCPlayBufferGroupData = pFWAVCDriverData->pFWAVCPlayBufferGroupDataList;
  2891.         if (pNextFWAVCPlayBufferGroupData != nil)
  2892.         {
  2893.             pPrevFWAVCPlayBufferGroupData =
  2894.                 pNextFWAVCPlayBufferGroupData->pPrevFWAVCPlayBufferGroupData;
  2895.  
  2896.             pNextFWAVCPlayBufferGroupData->pPrevFWAVCPlayBufferGroupData =
  2897.                 pFWAVCPlayBufferGroupData;
  2898.             pFWAVCPlayBufferGroupData->pNextFWAVCPlayBufferGroupData =
  2899.                 pNextFWAVCPlayBufferGroupData;
  2900.         }
  2901.         else
  2902.         {
  2903.             pPrevFWAVCPlayBufferGroupData = pFWAVCPlayBufferGroupData;
  2904.  
  2905.             pFWAVCDriverData->pFWAVCPlayBufferGroupDataList = pFWAVCPlayBufferGroupData;
  2906.         }
  2907.  
  2908.         pPrevFWAVCPlayBufferGroupData->pNextFWAVCPlayBufferGroupData =
  2909.             pFWAVCPlayBufferGroupData;
  2910.         pFWAVCPlayBufferGroupData->pPrevFWAVCPlayBufferGroupData =
  2911.             pPrevFWAVCPlayBufferGroupData;
  2912.     }
  2913.  
  2914.     return (pFWAVCPlayBufferGroupData);
  2915. }
  2916.  
  2917.  
  2918. ////////////////////////////////////////////////////////////////////////////////
  2919. //
  2920. // FWAVCDeallocatePlayBufferGroup
  2921. //
  2922. //   This routine deallocates a buffer group for playing.
  2923. //
  2924.  
  2925. static void    FWAVCDeallocatePlayBufferGroup(
  2926.     FWAVCPlayBufferGroupDataPtr    pFWAVCPlayBufferGroupData)
  2927. {
  2928.     if (pFWAVCPlayBufferGroupData != nil)
  2929.     {
  2930.         if (pFWAVCPlayBufferGroupData->bufferGroupUpdateDCLList != nil)
  2931.             PoolDeallocate ((Ptr) pFWAVCPlayBufferGroupData->bufferGroupUpdateDCLList);
  2932.  
  2933.         PoolDeallocate (pFWAVCPlayBufferGroupData);
  2934.     }
  2935. }
  2936.  
  2937.  
  2938. ////////////////////////////////////////////////////////////////////////////////
  2939. //
  2940. // FWAVCCreatePlayBufferGroupUpdateList
  2941. //
  2942. //   This routine creates the update list for a play buffer group.
  2943. //
  2944.  
  2945. static OSStatus    FWAVCCreatePlayBufferGroupUpdateList(
  2946.     FWAVCPlayBufferGroupDataPtr    pFWAVCPlayBufferGroupData)
  2947. {
  2948.     DCLCommandPtr                pDCLCommand,
  2949.                                 pLastDCLCommand;
  2950.     DCLCommandPtr                *updateDCLList,
  2951.                                 *pUpdateDCLListEntry;
  2952.     UInt32                        opcode;
  2953.     UInt32                        updateListSize;
  2954.     OSStatus                    status = noErr;
  2955.  
  2956.     // Loop through all DCL commands in buffer group and count all send packet DCL
  2957.     // commands.
  2958.     pDCLCommand = pFWAVCPlayBufferGroupData->pFirstBufferGroupDCLCommand;
  2959.     pLastDCLCommand = pFWAVCPlayBufferGroupData->pLastBufferGroupDCLCommand;
  2960.     updateListSize = 0;
  2961.     while (pDCLCommand != pLastDCLCommand)
  2962.     {
  2963.         opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
  2964.         if ((opcode == kDCLSendPacketStartOp) || (opcode == kDCLSendPacketOp))
  2965.             updateListSize++;
  2966.  
  2967.         pDCLCommand = pDCLCommand->pNextDCLCommand;
  2968.     }
  2969.     opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
  2970.     if ((opcode == kDCLSendPacketStartOp) || (opcode == kDCLSendPacketOp))
  2971.         updateListSize++;
  2972.  
  2973.     // Allocate update list.
  2974.     updateDCLList = (DCLCommandPtr *)
  2975.         PoolAllocateResident (updateListSize * sizeof (DCLCommandPtr), false);
  2976.     if (updateDCLList == nil)
  2977.         status = memFullErr;
  2978.  
  2979.     // Loop through all DCL commands in buffer group and add all send packet DCL
  2980.     // commands to update list.
  2981.     if (status == noErr)
  2982.     {
  2983.         pDCLCommand = pFWAVCPlayBufferGroupData->pFirstBufferGroupDCLCommand;
  2984.         pLastDCLCommand = pFWAVCPlayBufferGroupData->pLastBufferGroupDCLCommand;
  2985.         pUpdateDCLListEntry = updateDCLList;
  2986.  
  2987.         while (pDCLCommand != pLastDCLCommand)
  2988.         {
  2989.             opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
  2990.             if ((opcode == kDCLSendPacketStartOp) || (opcode == kDCLSendPacketOp))
  2991.                 *pUpdateDCLListEntry++ = pDCLCommand;
  2992.  
  2993.             pDCLCommand = pDCLCommand->pNextDCLCommand;
  2994.         }
  2995.  
  2996.         opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
  2997.         if ((opcode == kDCLSendPacketStartOp) || (opcode == kDCLSendPacketOp))
  2998.             *pUpdateDCLListEntry++ = pDCLCommand;
  2999.     }
  3000.  
  3001.     // Save update list.
  3002.     if (status == noErr)
  3003.     {
  3004.         pFWAVCPlayBufferGroupData->bufferGroupUpdateDCLList = updateDCLList;
  3005.         pFWAVCPlayBufferGroupData->updateListSize = updateListSize;
  3006.     }
  3007.     else
  3008.     {
  3009.         pFWAVCPlayBufferGroupData->bufferGroupUpdateDCLList = nil;
  3010.         pFWAVCPlayBufferGroupData->updateListSize = 0;
  3011.     }
  3012.  
  3013.     return (status);
  3014. }
  3015.  
  3016.  
  3017. ////////////////////////////////////////////////////////////////////////////////
  3018. //
  3019. // FWAVCAllocateDCLCommand
  3020. //
  3021. //   This routine allocates a DCL command.
  3022. //
  3023.  
  3024. static DCLCommandPtr    FWAVCAllocateDCLCommand(
  3025.     DCLCommandPoolPtr            pDCLCommandPool,
  3026.     UInt32                        dclSize)
  3027. {
  3028.     DCLCommandBlockPtr            pDCLCommandBlock;
  3029.     DCLCommandPtr                pDCLCommand;
  3030.  
  3031.     // Get last DCL command block in pool.
  3032.     pDCLCommandBlock = pDCLCommandPool->pLastDCLCommandBlock;
  3033.  
  3034.     // Check if we have enough room in command block.  Allocate a new block if there
  3035.     // is not enough room.
  3036.     if (pDCLCommandBlock != nil)
  3037.     {
  3038.         if (dclSize > (kDCLCommandPoolBlockSize - pDCLCommandBlock->blockLevel))
  3039.             pDCLCommandBlock = FWAVCAllocateDCLCommandBlock (pDCLCommandPool);
  3040.     }
  3041.     else
  3042.     {
  3043.         pDCLCommandBlock = FWAVCAllocateDCLCommandBlock (pDCLCommandPool);
  3044.     }
  3045.  
  3046.     // Allocate a DCL from the command block.
  3047.     if (pDCLCommandBlock != nil)
  3048.     {
  3049.         pDCLCommand =
  3050.             (DCLCommandPtr) (pDCLCommandBlock->block + pDCLCommandBlock->blockLevel);
  3051.         pDCLCommandBlock->blockLevel += dclSize;
  3052.     }
  3053.     else
  3054.     {
  3055.         pDCLCommand = nil;
  3056.     }
  3057.  
  3058.     return (pDCLCommand);
  3059. }
  3060.  
  3061.  
  3062. ////////////////////////////////////////////////////////////////////////////////
  3063. //
  3064. // FWAVCAllocateDCLCommandBlock
  3065. //
  3066. //   This routine allocates a DCL command block.
  3067. //
  3068.  
  3069. static DCLCommandBlockPtr    FWAVCAllocateDCLCommandBlock(
  3070.     DCLCommandPoolPtr            pDCLCommandPool)
  3071. {
  3072.     DCLCommandBlockPtr            pDCLCommandBlock = nil;
  3073.     Ptr                            block;
  3074.     OSStatus                    status = noErr;
  3075.  
  3076.     // Allocate command block record.
  3077.     pDCLCommandBlock =
  3078.         (DCLCommandBlockPtr) PoolAllocateResident (sizeof (DCLCommandBlock), true);
  3079.     if (pDCLCommandBlock == nil)
  3080.         status = memFullErr;
  3081.  
  3082.     // Allocate command block block.
  3083.     if (status == noErr)
  3084.     {
  3085.         block = PoolAllocateResident (kDCLCommandPoolBlockSize, false);
  3086.         if (block != nil)
  3087.             pDCLCommandBlock->block = block;
  3088.         else
  3089.             status = memFullErr;
  3090.     }
  3091.  
  3092.     // Insert command block into pool.
  3093.     if (status == noErr)
  3094.     {
  3095.         if (pDCLCommandPool->pFirstDCLCommandBlock != nil)
  3096.             pDCLCommandPool->pLastDCLCommandBlock->pNextDCLCommandBlock = pDCLCommandBlock;
  3097.         else
  3098.             pDCLCommandPool->pFirstDCLCommandBlock = pDCLCommandBlock;
  3099.  
  3100.         pDCLCommandPool->pLastDCLCommandBlock = pDCLCommandBlock;
  3101.         pDCLCommandBlock->pNextDCLCommandBlock = nil;
  3102.     }
  3103.  
  3104.     // Clean up on error.
  3105.     if ((status != noErr) && (pDCLCommandBlock != nil))
  3106.     {
  3107.         FWAVCDeallocateDCLCommandBlock (pDCLCommandBlock);
  3108.         pDCLCommandBlock = nil;
  3109.     }
  3110.  
  3111.     // Return results.
  3112.     return (pDCLCommandBlock);
  3113. }
  3114.  
  3115.  
  3116. ////////////////////////////////////////////////////////////////////////////////
  3117. //
  3118. // FWAVCDeallocateDCLCommandBlock
  3119. //
  3120. //   This routine deallocates a DCL command block.
  3121. //
  3122.  
  3123. static void    FWAVCDeallocateDCLCommandBlock(
  3124.     DCLCommandBlockPtr            pDCLCommandBlock)
  3125. {
  3126.     if (pDCLCommandBlock != nil)
  3127.     {
  3128.         // Deallocate command block block.
  3129.         if (pDCLCommandBlock->block != nil)
  3130.             PoolDeallocate (pDCLCommandBlock->block);
  3131.  
  3132.         // Deallocate command block record.
  3133.         PoolDeallocate ((Ptr) pDCLCommandBlock);
  3134.     }
  3135. }
  3136.  
  3137.  
  3138. ////////////////////////////////////////////////////////////////////////////////
  3139. //
  3140. // FWAVCAllocateDCLCommandPool
  3141. //
  3142. //   This routine allocates a DCL command pool.
  3143. //
  3144.  
  3145. static DCLCommandPoolPtr    FWAVCAllocateDCLCommandPool(void)
  3146. {
  3147.     DCLCommandPoolPtr            pDCLCommandPool;
  3148.  
  3149.     // Allocate DCL command pool record.
  3150.     pDCLCommandPool =
  3151.         (DCLCommandPoolPtr) PoolAllocateResident (sizeof (DCLCommandPool), true);
  3152.  
  3153.     return (pDCLCommandPool);
  3154. }
  3155.  
  3156.  
  3157. ////////////////////////////////////////////////////////////////////////////////
  3158. //
  3159. // FWAVCDeallocateDCLCommandPool
  3160. //
  3161. //   This routine deallocates a DCL command pool.
  3162. //
  3163.  
  3164. static void    FWAVCDeallocateDCLCommandPool(
  3165.     DCLCommandPoolPtr            pDCLCommandPool)
  3166. {
  3167.     DCLCommandBlockPtr            pDCLCommandBlock,
  3168.                                 pNextDCLCommandBlock;
  3169.  
  3170.     if (pDCLCommandPool != nil)
  3171.     {
  3172.         // Deallocate all command blocks.
  3173.         pDCLCommandBlock = pDCLCommandPool->pFirstDCLCommandBlock;
  3174.         while (pDCLCommandBlock != nil)
  3175.         {
  3176.             pNextDCLCommandBlock = pDCLCommandBlock->pNextDCLCommandBlock;
  3177.             FWAVCDeallocateDCLCommandBlock (pDCLCommandBlock);
  3178.             pDCLCommandBlock = pNextDCLCommandBlock;
  3179.         }
  3180.  
  3181.         // Deallocate command pool record.
  3182.         PoolDeallocate ((Ptr) pDCLCommandPool);
  3183.     }
  3184. }
  3185.  
  3186.  
  3187. ////////////////////////////////////////////////////////////////////////////////
  3188. //
  3189. // FWAVCAddCycleTimeToCycleTime
  3190. //
  3191. //   This routine adds the two given cycle times.
  3192. //
  3193.  
  3194. static UInt32    FWAVCAddCycleTimeToCycleTime(
  3195.     UInt32                        cycleTime1,
  3196.     UInt32                        cycleTime2)
  3197. {
  3198.     UInt32                        secondCount,
  3199.                                 cycleCount,
  3200.                                 cycleOffset;
  3201.     UInt32                        cycleTime;
  3202.  
  3203.     // Add cycle offsets.
  3204.     cycleOffset = (cycleTime1 & 0x0FFF) + (cycleTime2 & 0x0FFF);
  3205.  
  3206.     // Add cycle counts.
  3207.     cycleCount = (cycleTime1 & 0x01FFF000) + (cycleTime2 & 0x01FFF000);
  3208.  
  3209.     // Add any carry over from cycle offset to cycle count.
  3210.     if (cycleOffset > 3071)
  3211.     {
  3212.         cycleCount += 0x1000;
  3213.         cycleOffset -= 3072;
  3214.     }
  3215.  
  3216.     // Add secondCounts.
  3217.     secondCount = (cycleTime1 & 0xE0000000) + (cycleTime2 & 0xE0000000);
  3218.  
  3219.     // Add any carry over from cycle count to secondCount.
  3220.     if (cycleCount > (8000 << 12))
  3221.     {
  3222.         secondCount += 0x20000000;
  3223.         cycleCount -= (8000 << 12);
  3224.     }
  3225.  
  3226.     // Put everything together into cycle time.
  3227.     cycleTime = secondCount | cycleCount | cycleOffset;
  3228.  
  3229.     return (cycleTime);
  3230. }
  3231.  
  3232.  
  3233. ////////////////////////////////////////////////////////////////////////////////
  3234. //
  3235. // FWAVCSubtractCycleTimeFromCycleTime
  3236. //
  3237. //   This routine subtracts the two given cycle times.
  3238. //
  3239.  
  3240. static UInt32    FWAVCSubtractCycleTimeFromCycleTime(
  3241.     UInt32                        cycleTime1,
  3242.     UInt32                        cycleTime2)
  3243. {
  3244.     SInt32                        secondCount,
  3245.                                 cycleCount,
  3246.                                 cycleOffset;
  3247.     UInt32                        cycleTime;
  3248.  
  3249.     // Subtract cycle offsets.
  3250.     cycleOffset = (cycleTime1 & 0x0FFF) - (cycleTime2 & 0x0FFF);
  3251.  
  3252.     // Subtract cycle counts.
  3253.     cycleCount = (cycleTime1 & 0x01FFF000) - (cycleTime2 & 0x01FFF000);
  3254.  
  3255.     // Subtract any borrow over from cycle offset to cycle count.
  3256.     
  3257.     if (cycleOffset < 0)
  3258.     {
  3259.         cycleCount -= 0x1000;
  3260.         cycleOffset += 3072;
  3261.     }
  3262.  
  3263.     // Subtract secondCounts.
  3264.     secondCount = (cycleTime1 & 0xE0000000) - (cycleTime2 & 0xE0000000);
  3265.  
  3266.     // Subtract any borrow over from cycle count to secondCount.
  3267.     if (cycleCount < 0)
  3268.     {
  3269.         secondCount -= 0x20000000;
  3270.         cycleCount += (8000 << 12);
  3271.     }
  3272.  
  3273.     // Put everything together into cycle time.
  3274.     cycleTime = secondCount | cycleCount | cycleOffset;
  3275.  
  3276.     return (cycleTime);
  3277. }
  3278.  
  3279.  
  3280. ////////////////////////////////////////////////////////////////////////////////
  3281. //
  3282. // FWAVCConvertFractionalSecondsToCycleTime
  3283. //
  3284. //   This routine converts a time represented in fractional seconds to a time
  3285. // represented in cycle timer format.
  3286. //
  3287.  
  3288. static UInt32    FWAVCConvertFractionalSecondsToCycleTime(
  3289.     UInt32                        secondsNumerator,
  3290.     UInt32                        secondsDenominator)
  3291. {
  3292.     float                        fSecondCount;
  3293.     float                        fCycleCount;
  3294.     float                        fCycleOffset;
  3295.     UInt32                        iSecondsCount;
  3296.     UInt32                        iCycleCount;
  3297.     UInt32                        iCycleOffset;
  3298.     UInt32                        secondsCycleTime;
  3299.  
  3300.     // Convert fractional seconds into floating point and compute seconds count.
  3301.     fSecondCount = ((float) secondsNumerator) / ((float) secondsDenominator);
  3302.     iSecondsCount = (UInt32) fSecondCount;
  3303.  
  3304.     // Subtract whole seconds out of fSecondCount and convert to cycle count.
  3305.     fCycleCount = (fSecondCount - ((float) iSecondsCount)) * 8000.0;
  3306.     iCycleCount = (UInt32) fCycleCount;
  3307.  
  3308.     // Subtract whole cycles out of fCycleCount and convert to cycle offset.
  3309.     fCycleOffset = (fCycleCount - ((float) iCycleCount)) * 3072.0;
  3310.     iCycleOffset = (UInt32) fCycleOffset;
  3311.  
  3312.     // Convert to cycle timer format.
  3313.     secondsCycleTime = (iSecondsCount << 25) | (iCycleCount << 12) | iCycleOffset;
  3314.  
  3315.     return (secondsCycleTime);
  3316. }
  3317.